2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <app_control_internal.h>
20 #include <aul_job_scheduler.h>
23 #include <service_app.h>
26 #include <vconf-internal-keys.h>
28 #include <app_core_base.hh>
29 #include <app_event_internal.hh>
34 #include <type_traits>
36 #include "service_app_extension.h"
37 #include "service_app_internal.h"
39 #include "job-manager.hh"
40 #include "log-private.hh"
43 using namespace tizen_cpp;
47 const char* __error_to_string(app_error_e error) {
51 case APP_ERROR_INVALID_PARAMETER:
52 return "INVALID_PARAMETER";
53 case APP_ERROR_OUT_OF_MEMORY: // LCOV_EXCL_LINE
54 return "OUT_OF_MEMORY"; // LCOV_EXCL_LINE
55 case APP_ERROR_INVALID_CONTEXT:
56 return "INVALID_CONTEXT";
57 case APP_ERROR_NO_SUCH_FILE: // LCOV_EXCL_LINE
58 return "NO_SUCH_FILE"; // LCOV_EXCL_LINE
59 case APP_ERROR_ALREADY_RUNNING:
60 return "ALREADY_RUNNING";
61 default: // LCOV_EXCL_LINE
62 return "UNKNOWN"; // LCOV_EXCL_LINE
66 int __on_error(app_error_e error, const char* function,
67 const char* description) {
69 _E("[%s] %s(0x%08x) : %s",
70 function, __error_to_string(error), error, description);
72 _E("[%s] %s(0x%08x)", function, __error_to_string(error), error);
78 constexpr int APP_EVENT_MAX = static_cast<int>(IAppCore::IEvent::Type::END);
79 constexpr IAppCore::IEvent::Type __app_event_converter[APP_EVENT_MAX] = {
80 [APP_EVENT_LOW_MEMORY] = IAppCore::IEvent::Type::LOW_MEMORY,
81 [APP_EVENT_LOW_BATTERY] = IAppCore::IEvent::Type::LOW_BATTERY,
82 [APP_EVENT_LANGUAGE_CHANGED] = IAppCore::IEvent::Type::LANG_CHANGE,
83 [APP_EVENT_DEVICE_ORIENTATION_CHANGED] =
84 IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED,
85 [APP_EVENT_REGION_FORMAT_CHANGED] = IAppCore::IEvent::Type::REGION_CHANGE,
86 [APP_EVENT_SUSPENDED_STATE_CHANGED] =
87 IAppCore::IEvent::Type::SUSPENDED_STATE_CHANGE,
88 [APP_EVENT_UPDATE_REQUESTED] = IAppCore::IEvent::Type::UPDATE_REQUESTED,
89 [APP_EVENT_TIME_ZONE_CHANGED] =
90 IAppCore::IEvent::Type::TIME_ZONE_CHANGED,
93 class AppContext : public AppCoreBase {
96 APP_STATE_NOT_RUNNING,
101 AppContext(service_app_lifecycle_callback_s callback,
102 service_app_loop_method_s method, void* data)
103 : callback_(callback), method_(method), data_(data) {
104 state_ = APP_STATE_CREATING;
107 void Run(int argc, char** argv) override {
108 SetAppState(APP_STATE_RUNNING);
109 AppCoreBase::Run(argc, argv);
110 SetAppState(APP_STATE_NOT_RUNNING);
113 int OnReceive(aul_type type, tizen_base::Bundle b) override {
114 AppCoreBase::OnReceive(type, std::move(b));
116 if (type == AUL_TERMINATE_BGAPP) {
126 int OnCreate() override {
127 _W("service_app_create()");
128 AppCoreBase::OnCreate();
130 if (callback_.create == nullptr || callback_.create(data_) == false) {
131 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__,
132 "service_app_create_cb() returns false");
135 return APP_ERROR_NONE;
138 int OnControl(tizen_base::Bundle b) override {
139 _W("service_app_control()");
140 AppCoreBase::OnControl(b);
142 std::string job_id = b.GetString(AUL_K_JOB_ID);
143 if (!job_id.empty()) {
144 _D("[__JOB__] Job(%s)", job_id.c_str()); // LCOV_EXCL_LINE
148 app_control_h app_control = nullptr;
149 if (app_control_create_event(b.GetHandle(), &app_control) != 0)
152 if (callback_.app_control)
153 callback_.app_control(app_control, data_);
155 app_control_destroy(app_control);
160 int OnTerminate() override {
161 _W("service_app_terminate()");
162 if (callback_.terminate)
163 callback_.terminate(data_);
165 AppCoreBase::OnTerminate();
167 return APP_ERROR_NONE;
170 void OnLoopInit(int argc, char** argv) override {
172 method_.init(argc, argv, data_); // LCOV_EXCL_LINE
179 void OnLoopFinish() override {
181 method_.fini(); // LCOV_EXCL_LINE
183 _W("ecore_shutdown");
188 void OnLoopRun() override {
190 method_.run(data_); // LCOV_EXCL_LINE
192 ecore_main_loop_begin();
195 void OnLoopExit() override {
196 SetAppState(APP_STATE_NOT_RUNNING);
198 method_.exit(data_); // LCOV_EXCL_LINE
200 ecore_main_loop_thread_safe_call_sync([](void* data) -> void* {
201 ecore_main_loop_quit();
207 AppState GetAppState() const {
208 std::lock_guard<std::recursive_mutex> lock(mutex_);
212 void SetAppState(AppState state) {
213 std::lock_guard<std::recursive_mutex> lock(mutex_);
218 service_app_lifecycle_callback_s callback_;
219 service_app_loop_method_s method_;
221 AppState state_ = APP_STATE_NOT_RUNNING;
222 mutable std::recursive_mutex mutex_;
225 std::unique_ptr<AppContext> __context;
226 std::list<std::shared_ptr<AppEvent>> __pending_app_events;
227 JobManager __job_manager;
231 extern "C" EXPORT_API int service_app_main_ext(int argc, char** argv,
232 service_app_lifecycle_callback_s* callback,
233 service_app_loop_method_s* method, void* user_data) {
234 if (argc < 1 || argv == nullptr || callback == nullptr || method == nullptr)
235 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, nullptr);
237 if (callback->create == nullptr) {
238 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
239 "service_app_create_cb() callback must be registered");
242 if (__context.get() != nullptr &&
243 __context->GetAppState() != AppContext::APP_STATE_NOT_RUNNING)
244 return __on_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, nullptr);
247 __context = std::make_unique<AppContext>(*callback, *method, user_data);
248 for (auto& i : __pending_app_events) {
249 __context->AddEvent(i);
251 __context->Run(argc, argv);
252 } catch(std::runtime_error& e) {
254 __context->SetAppState(AppContext::APP_STATE_NOT_RUNNING);
255 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, nullptr);
259 __job_manager.FinishAllJobs();
260 return APP_ERROR_NONE;
263 extern "C" EXPORT_API int service_app_main(int argc, char** argv,
264 service_app_lifecycle_callback_s* callback, void* user_data) {
265 service_app_loop_method_s method = { nullptr, };
266 _W("service_app_main()");
267 return service_app_main_ext(argc, argv, callback, &method, user_data);
270 extern "C" EXPORT_API void service_app_exit(void) {
271 _W("service_app_exit()");
272 if (__context.get() &&
273 __context->GetAppState() == AppContext::APP_STATE_RUNNING)
277 extern "C" EXPORT_API int service_app_add_event_handler(
278 app_event_handler_h* event_handler, app_event_type_e event_type,
279 app_event_cb callback, void *user_data) {
280 if (event_handler == nullptr || callback == nullptr) {
281 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
285 if (event_type < APP_EVENT_LOW_MEMORY ||
286 event_type > APP_EVENT_TIME_ZONE_CHANGED ||
287 event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED) {
288 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
289 "invalid event type");
292 auto* ae = new (std::nothrow) AppEvent(__app_event_converter[event_type],
293 callback, user_data);
296 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__,
297 "failed to create handler");
301 auto* h = new (std::nothrow) std::shared_ptr<AppEvent>(ae);
305 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__,
306 "failed to create handler");
310 if (__context.get() &&
311 __context->GetAppState() == AppContext::APP_STATE_RUNNING) {
312 __context->AddEvent(*h);
314 __pending_app_events.push_back(*h);
317 *event_handler = reinterpret_cast<app_event_handler_h>(h);
319 return APP_ERROR_NONE;
322 extern "C" EXPORT_API int service_app_remove_event_handler(
323 app_event_handler_h event_handler) {
324 if (event_handler == nullptr)
325 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, nullptr);
327 auto* eb = reinterpret_cast<std::shared_ptr<AppEvent>*>(event_handler);
328 auto type = (*eb)->GetType();
330 if (type < IAppCore::IEvent::Type::LOW_MEMORY ||
331 type > IAppCore::IEvent::Type::TIME_ZONE_CHANGED ||
332 type == IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED)
333 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, nullptr); // LCOV_EXCL_LINE
335 if (__context.get() &&
336 __context->GetAppState() == AppContext::APP_STATE_RUNNING) {
337 if (!__context->RemoveEvent(*eb)) {
339 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
340 "invalid raw handler");
344 __pending_app_events.remove(*eb);
349 return APP_ERROR_NONE;
352 extern "C" EXPORT_API void service_app_exit_without_restart(void) {
353 if (__context.get() &&
354 __context->GetAppState() == AppContext::APP_STATE_RUNNING) {
355 aul_status_update_v2(STATUS_NORESTART);
360 extern "C" EXPORT_API service_app_job_h service_app_add_job_handler(
361 const char* job_id, service_app_job_cb callback, void* user_data) {
362 if (job_id == nullptr || callback == nullptr) {
363 _E("Invalid parameter");
367 auto* handle = new (std::nothrow) JobHandler(job_id, callback, user_data);
368 if (handle == nullptr) {
375 __job_manager.AddJobHandler(handle);
376 __job_manager.FlushPendingJob(job_id);
380 extern "C" EXPORT_API int service_app_remove_job_handler(
381 service_app_job_h handle) {
382 if (handle == nullptr) {
383 _E("Invalid parameter");
384 return APP_ERROR_INVALID_PARAMETER;
387 auto* h = static_cast<JobHandler*>(handle);
388 if (!__job_manager.ExistJobHandler(h)) {
390 _E("Invalid parameter");
391 return APP_ERROR_INVALID_PARAMETER;
395 __job_manager.RemoveJobHandler(h);
397 return APP_ERROR_NONE;
400 extern "C" EXPORT_API int service_app_job_raise(int job_status,
401 const char* job_id, bundle* job_data) {
402 if (job_status < SERVICE_APP_JOB_STATUS_START ||
403 job_status > SERVICE_APP_JOB_STATUS_STOP ||
404 job_id == nullptr || job_data == nullptr) {
405 _E("Invalid parameter");
406 return APP_ERROR_INVALID_PARAMETER;
409 auto job = std::make_shared<Job>(job_status, job_id,
410 tizen_base::Bundle(job_data, true, true));
411 if (job == nullptr) {
414 return APP_ERROR_OUT_OF_MEMORY;
418 __job_manager.Do(job);
419 return APP_ERROR_NONE;
422 extern "C" EXPORT_API int service_app_job_finished(const char* job_id) {
423 if (job_id == nullptr) {
424 _E("Invalid parameter");
425 return APP_ERROR_INVALID_PARAMETER;
428 if (__job_manager.Finish(job_id) != 0)
429 return APP_ERROR_INVALID_CONTEXT; // LCOV_EXCL_LINE
431 return APP_ERROR_NONE;