Fix static analysis issues
[platform/core/appfw/appcore-agent.git] / src / service_app_main.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <Ecore.h>
18 #include <app_control_internal.h>
19 #include <aul.h>
20 #include <aul_job_scheduler.h>
21 #include <dlog.h>
22 #include <glib.h>
23 #include <service_app.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <vconf-internal-keys.h>
27
28 #include <app_core_base.hh>
29 #include <app_event_internal.hh>
30
31 #include <list>
32 #include <memory>
33 #include <mutex>
34 #include <type_traits>
35
36 #include "service_app_extension.h"
37 #include "service_app_internal.h"
38
39 #include "job-manager.hh"
40 #include "log-private.hh"
41 #include <stdexcept>
42
43 using namespace tizen_cpp;
44
45 namespace {
46
47 const char* __error_to_string(app_error_e error) {
48   switch (error) {
49     case APP_ERROR_NONE:
50       return "NONE";
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
63   }
64 }
65
66 int __on_error(app_error_e error, const char* function,
67     const char* description) {
68   if (description) {
69     _E("[%s] %s(0x%08x) : %s",
70         function, __error_to_string(error), error, description);
71   } else {
72     _E("[%s] %s(0x%08x)", function, __error_to_string(error), error);
73   }
74
75   return error;
76 }
77
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,
91 };
92
93 class AppContext : public AppCoreBase {
94  public:
95   enum AppState {
96     APP_STATE_NOT_RUNNING,
97     APP_STATE_CREATING,
98     APP_STATE_RUNNING,
99   };
100
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;
105   }
106
107   void Run(int argc, char** argv) override {
108     SetAppState(APP_STATE_RUNNING);
109     AppCoreBase::Run(argc, argv);
110     SetAppState(APP_STATE_NOT_RUNNING);
111   }
112
113   int OnReceive(aul_type type, tizen_base::Bundle b) override {
114     AppCoreBase::OnReceive(type, std::move(b));
115
116     if (type == AUL_TERMINATE_BGAPP) {
117       // LCOV_EXCL_START
118       Exit();
119       return 0;
120       // LCOV_EXCL_STOP
121     }
122
123     return 0;
124   }
125
126   int OnCreate() override {
127     _W("service_app_create()");
128     AppCoreBase::OnCreate();
129
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");
133     }
134
135     return APP_ERROR_NONE;
136   }
137
138   int OnControl(tizen_base::Bundle b) override {
139     _W("service_app_control()");
140     AppCoreBase::OnControl(b);
141
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
145       return 0;
146     }
147
148     app_control_h app_control = nullptr;
149     if (app_control_create_event(b.GetHandle(), &app_control) != 0)
150       return -1;
151
152     if (callback_.app_control)
153       callback_.app_control(app_control, data_);
154
155     app_control_destroy(app_control);
156
157     return 0;
158   }
159
160   int OnTerminate() override {
161     _W("service_app_terminate()");
162     if (callback_.terminate)
163       callback_.terminate(data_);
164
165     AppCoreBase::OnTerminate();
166
167     return APP_ERROR_NONE;
168   }
169
170   void OnLoopInit(int argc, char** argv) override {
171     if (method_.init) {
172       method_.init(argc, argv, data_);  // LCOV_EXCL_LINE
173     } else {
174       _W("ecore_init");
175       ecore_init();
176     }
177   }
178
179   void OnLoopFinish() override {
180     if (method_.fini) {
181       method_.fini();  // LCOV_EXCL_LINE
182     } else {
183       _W("ecore_shutdown");
184       ecore_shutdown();
185     }
186   }
187
188   void OnLoopRun() override {
189     if (method_.run)
190       method_.run(data_);  // LCOV_EXCL_LINE
191     else
192       ecore_main_loop_begin();
193   }
194
195   void OnLoopExit() override {
196     SetAppState(APP_STATE_NOT_RUNNING);
197     if (method_.exit) {
198       method_.exit(data_);  // LCOV_EXCL_LINE
199     } else {
200       ecore_main_loop_thread_safe_call_sync([](void* data) -> void* {
201         ecore_main_loop_quit();
202         return nullptr;
203       }, nullptr);
204     }
205   }
206
207   AppState GetAppState() const {
208     std::lock_guard<std::recursive_mutex> lock(mutex_);
209     return state_;
210   }
211
212   void SetAppState(AppState state) {
213     std::lock_guard<std::recursive_mutex> lock(mutex_);
214     state_ = state;
215   }
216
217  private:
218   service_app_lifecycle_callback_s callback_;
219   service_app_loop_method_s method_;
220   void* data_;
221   AppState state_ = APP_STATE_NOT_RUNNING;
222   mutable std::recursive_mutex mutex_;
223 };
224
225 std::unique_ptr<AppContext> __context;
226 std::list<std::shared_ptr<AppEvent>> __pending_app_events;
227 JobManager __job_manager;
228
229 }  // namespace
230
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);
236
237   if (callback->create == nullptr) {
238     return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
239         "service_app_create_cb() callback must be registered");
240   }
241
242   if (__context.get() != nullptr &&
243       __context->GetAppState() != AppContext::APP_STATE_NOT_RUNNING)
244     return __on_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, nullptr);
245
246   try {
247     __context = std::make_unique<AppContext>(*callback, *method, user_data);
248     for (auto& i : __pending_app_events) {
249       __context->AddEvent(i);
250     }
251     __context->Run(argc, argv);
252   } catch(std::runtime_error& e) {
253     // LCOV_EXCL_START
254     __context->SetAppState(AppContext::APP_STATE_NOT_RUNNING);
255     return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, nullptr);
256     // LCOV_EXCL_STOP
257   }
258
259   __job_manager.FinishAllJobs();
260   return APP_ERROR_NONE;
261 }
262
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);
268 }
269
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)
274     __context->Exit();
275 }
276
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__,
282         "null parameter");
283   }
284
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");
290   }
291
292   auto* ae = new (std::nothrow) AppEvent(__app_event_converter[event_type],
293       callback, user_data);
294   if (!ae) {
295     // LCOV_EXCL_START
296     return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__,
297         "failed to create handler");
298     // LCOV_EXCL_STOP
299   }
300
301   auto* h = new (std::nothrow) std::shared_ptr<AppEvent>(ae);
302   if (!h) {
303     // LCOV_EXCL_START
304     delete ae;
305     return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__,
306         "failed to create handler");
307     // LCOV_EXCL_STOP
308   }
309
310   if (__context.get() &&
311       __context->GetAppState() == AppContext::APP_STATE_RUNNING) {
312     __context->AddEvent(*h);
313   } else {
314     __pending_app_events.push_back(*h);
315   }
316
317   *event_handler = reinterpret_cast<app_event_handler_h>(h);
318
319   return APP_ERROR_NONE;
320 }
321
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);
326
327   auto* eb = reinterpret_cast<std::shared_ptr<AppEvent>*>(event_handler);
328   auto type = (*eb)->GetType();
329
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
334
335   if (__context.get() &&
336       __context->GetAppState() == AppContext::APP_STATE_RUNNING) {
337     if (!__context->RemoveEvent(*eb)) {
338       // LCOV_EXCL_START
339       return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
340           "invalid raw handler");
341       // LCOV_EXCL_STOP
342     }
343   } else {
344     __pending_app_events.remove(*eb);
345   }
346
347   delete eb;
348
349   return APP_ERROR_NONE;
350 }
351
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);
356     __context->Exit();
357   }
358 }
359
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");
364     return nullptr;
365   }
366
367   auto* handle = new (std::nothrow) JobHandler(job_id, callback, user_data);
368   if (handle == nullptr) {
369     // LCOV_EXCL_START
370     _E("Out of memory");
371     return nullptr;
372     // LCOV_EXCL_STOP
373   }
374
375   __job_manager.AddJobHandler(handle);
376   __job_manager.FlushPendingJob(job_id);
377   return handle;
378 }
379
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;
385   }
386
387   auto* h = static_cast<JobHandler*>(handle);
388   if (!__job_manager.ExistJobHandler(h)) {
389     // LCOV_EXCL_START
390     _E("Invalid parameter");
391     return APP_ERROR_INVALID_PARAMETER;
392     // LCOV_EXCL_STOP
393   }
394
395   __job_manager.RemoveJobHandler(h);
396   delete h;
397   return APP_ERROR_NONE;
398 }
399
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;
407   }
408
409   auto job = std::make_shared<Job>(job_status, job_id,
410       tizen_base::Bundle(job_data, true, true));
411   if (job == nullptr) {
412     // LCOV_EXCL_START
413     _E("Out of memory");
414     return APP_ERROR_OUT_OF_MEMORY;
415     // LCOV_EXCL_STOP
416   }
417
418   __job_manager.Do(job);
419   return APP_ERROR_NONE;
420 }
421
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;
426   }
427
428   if (__job_manager.Finish(job_id) != 0)
429     return APP_ERROR_INVALID_CONTEXT;  // LCOV_EXCL_LINE
430
431   return APP_ERROR_NONE;
432 }