540b944264cc93b0e73497e1d177b9375e97fda1
[platform/core/appfw/app-core.git] / tizen-cpp / app-core-cpp / app_core_base.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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 "app-core-cpp/app_core_base.hh"
18
19 #include <aul.h>
20 #include <aul_app_lifecycle.h>
21 #include <aul_watchdog.h>
22 #include <bundle_internal.h>
23 #include <dlfcn.h>
24 #include <errno.h>
25 #include <execinfo.h>
26 #include <gio/gio.h>
27 #include <glib-unix.h>
28 #include <glib.h>
29 #include <libintl.h>
30 #include <linux/limits.h>
31 #include <locale.h>
32 #include <malloc.h>
33 #include <sensor_internal.h>
34 #include <signal.h>
35 #include <stdbool.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <system_info.h>
40 #include <ttrace.h>
41 #include <unistd.h>
42 #include <vconf.h>
43
44 #include <algorithm>
45 #include <cstring>
46 #include <list>
47 #include <map>
48 #include <memory>
49 #include <set>
50 #include <sstream>
51 #include <utility>
52 #include <vector>
53
54 #include "app-core-cpp/app_core_plugin_private.hh"
55 #include "app-core-cpp/sigterm_handler_private.hh"
56 #include "common/glib_private.hh"
57 #include "common/log_private.hh"
58
59 #define SIGRTANR (SIGRTMIN + 3)
60 #undef _ERR
61 #define _ERR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
62
63 extern "C" void aul_finalize();
64 namespace tizen_cpp {
65
66 AppCoreBase* AppCoreBase::context_ = nullptr;
67
68 namespace {
69
70 constexpr const int BACKTRACE_BUFFER_SIZE = 128;
71
72 void PrintBacktrace() {
73   char* buffer[BACKTRACE_BUFFER_SIZE];
74   int nptrs = backtrace(reinterpret_cast<void**>(buffer),
75       BACKTRACE_BUFFER_SIZE);
76   _ERR("backtrace() returned %d addresses", nptrs - 4);
77
78   // To print numbers, we use backtrace_symbols() instead of backtrace_symbols_fd().
79   // If there is an issues related to the memory, we cannot use backtrace_symbols().
80   // backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
81   char** strings = backtrace_symbols(reinterpret_cast<void**>(buffer), nptrs);
82   if (strings == nullptr) {
83     perror("backtrace_symbols");
84     return;
85   }
86
87   Dl_info info;
88   for (int i = 4; i < nptrs; ++i) {
89     dladdr(buffer[i], &info);
90     _ERR("[%3d] %s %s",
91         i - 4, info.dli_sname ? info.dli_sname : "?", strings[i]);
92   }
93   free(strings);
94 }
95
96 class ExitHandler {
97  public:
98   ExitHandler() {
99     on_exit(OnExit, this);
100   }
101
102  private:
103   static void OnExit(int status, void *user_data) {
104     if (status != 127)
105       return;
106
107     PrintBacktrace();
108
109     _ERR("%s(%d) abort()", __FUNCTION__, __LINE__);
110     abort();
111   }
112 };
113
114 ExitHandler exit_handler;
115
116 class AnrMonitor {
117  public:
118   AnrMonitor() {
119     struct sigaction action;
120     memset(&action, '\0', sizeof(action));
121     sigemptyset(&action.sa_mask);
122     action.sa_flags = SA_RESTART;
123     action.sa_handler = SignalHandler;
124
125     if (sigaction(SIGRTANR, &action, &old_action_) != 0)
126       _E("sigaction() is failed. errno(%d)", errno);
127   }
128
129   ~AnrMonitor() {
130     if (sigaction(SIGRTANR, &old_action_, nullptr) != 0)
131       _W("sigaction() is failed. errno(%d)", errno);
132   }
133
134  private:
135   static void SignalHandler(int signo) {
136     static unsigned int count;
137     _ERR("===================================================================");
138     _ERR("=================== Application Not Responding ====================");
139     PrintBacktrace();
140     _ERR("============== Application did not respond %d times ===============",
141         ++count);
142     _ERR("===================================================================");
143   }
144
145  private:
146   struct sigaction old_action_;
147 };
148
149 AnrMonitor anr_monitor;
150 internal::SigtermHandler sigterm_handler;
151
152 enum TizenProfile {
153   Unknown = 0x00,
154   Mobile = 0x01,
155   Wearable = 0x02,
156   Tv = 0x04,
157   Ivi = 0x08,
158   Common = 0x10,
159 };
160
161 TizenProfile TizenProfileGet() {
162   static TizenProfile profile = TizenProfile::Unknown;
163   if (__builtin_expect(profile != TizenProfile::Unknown, 1))
164     return profile;
165
166   char* profile_name = nullptr;
167   system_info_get_platform_string("http://tizen.org/feature/profile",
168       &profile_name);
169   if (profile_name == nullptr)
170     return profile;
171
172   switch (*profile_name) {
173   case 'm':
174   case 'M':
175     profile = TizenProfile::Mobile;
176     break;
177   case 'w':
178   case 'W':
179     profile = TizenProfile::Wearable;
180     break;
181   case 't':
182   case 'T':
183     profile = TizenProfile::Tv;
184     break;
185   case 'i':
186   case 'I':
187     profile = TizenProfile::Ivi;
188     break;
189   default:
190     profile = TizenProfile::Common;
191     break;
192   }
193   free(profile_name);
194
195   return profile;
196 }
197
198 constexpr const char PATH_LOCALE[] = "locale";
199 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
200 constexpr const char RESOURCED_FREEZER_PATH[] =
201     "/Org/Tizen/ResourceD/Freezer";
202 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
203     "org.tizen.resourced.freezer";
204 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
205     "FreezerState";
206
207 struct Rotation {
208   int conn;
209   int lock;
210   int ref;
211   tizen_cpp::AppCoreBase::RotationState rm;
212   int charger_status;
213   bool initialized;
214 };
215
216 Rotation __rotation;
217 GDBusConnection* __bus;
218 guint __suspend_dbus_handler_initialized;
219 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
220
221 }  // namespace
222
223 class AppCoreBase::EventBase::Impl {
224  private:
225   friend class AppCoreBase;
226   Type type_ = IEvent::Type::START;
227   std::string str_val_;
228   int val_ = -1;
229 };
230
231 class AppCoreBase::Impl {
232  public:
233   explicit Impl(AppCoreBase* parent) : parent_(parent) {
234     if (TizenProfileGet() & TizenProfile::Wearable)
235       feature_ |= FEATURE_CHARGER_STATUS;
236     if (!(TizenProfileGet() & TizenProfile::Tv))
237       feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
238   }
239
240  private:
241   void UnregisterRotationChangedEvent();
242   void RegisterRotationChangedEvent();
243   std::string GetAppName(const char* appid);
244   std::string GetLocaleResourceDir();
245   void UpdateLang();
246   void UpdateRegion();
247   std::list<std::string> SplitLanguage(const std::string& lang);
248   std::string GetLanguage(std::string lang);
249   void AppendDefaultLangs(std::vector<std::string>& lang_set);
250   std::string GetStringBefore(const char* str, const char* delim);
251   std::map<std::string, std::set<std::string>> GetLangTable();
252   void AppendLangs(const std::string& lang, std::vector<std::string>& lang_set,
253       std::map<std::string, std::set<std::string>>& table);
254   void ChangeLang();
255   void OnFreezerSignal();
256
257   template <class T>
258   void InvokeCallback(T event, IEvent::Type type) {
259     for (auto& i : events_) {
260       if (i->GetType() != type)
261         continue;
262
263       if (i->GetVal(event) != event ||
264           type == IEvent::Type::START ||
265           type == IEvent::Type::UPDATE_REQUESTED) {
266         i->SetVal(event);
267         i->OnEvent(event);
268       }
269     }
270   }
271
272   static void InitSuspendDbusHandler(gpointer data);
273   static gboolean InitSuspendCb(gpointer data);
274   static gboolean InvokeLangChangeCb(gpointer data);
275   static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
276       const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
277   static void OnLowBatteryCb(keynode_t* key, void* data);
278   static void LockCb(keynode_t* node, void* user_data);
279   static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
280       sensor_data_t* data, void* user_data);
281   static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
282   static void LanguageChangeCb(keynode_t* key, void* data);
283   static void RegionChangeCb(keynode_t* key, void* data);
284   static void LowMemoryCb(keynode_t* key, void* data);
285   void InitRotation();
286   void FiniRotation();
287   RotationState GetRm(sensor_data_t data);
288   void VerifyLanguage();
289   void SetDefaultEvents();
290   void UnsetDefaultEvents();
291   void PluginInit(int argc, char** argv);
292   void PluginFini();
293
294  private:
295   friend class AppCoreBase;
296   AppCoreBase* parent_ = nullptr;
297
298   int argc_ = 0;
299   char** argv_ = nullptr;
300   bool suspended_state_ = false;
301   bool allowed_bg_ = false;
302   bool dirty_ = false;
303   unsigned int tid_ = 0;
304   std::list<std::shared_ptr<EventBase>> events_;
305   std::string locale_dir_;
306   guint sid_ = 0;
307   int feature_ = 0;
308   IAppCore* core_delegator_ = nullptr;
309   IMainLoop* loop_delegator_ = nullptr;
310   guint signal_handler_source_ = 0;
311   std::unique_ptr<AppCorePlugin> plugin_;
312 };
313
314 AppCoreBase::EventBase::EventBase(Type type)
315     : impl_(std::make_unique<EventBase::Impl>()) {
316   impl_->type_ = type;
317 }
318
319 AppCoreBase::EventBase::~EventBase() = default;
320
321 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
322   return impl_->type_;
323 }
324
325 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
326   return impl_->str_val_;
327 }
328
329 int AppCoreBase::EventBase::GetVal(int cur) const {
330   return impl_->val_;
331 }
332
333 void AppCoreBase::EventBase::SetVal(std::string val) {
334   impl_->str_val_ = std::move(val);
335 }
336
337 void AppCoreBase::EventBase::SetVal(int val) {
338   impl_->val_ = std::move(val);
339 }
340
341 AppCoreBase::AppCoreBase()
342     : impl_(std::make_unique<AppCoreBase::Impl>(this)) {
343   if (context_ != nullptr) {
344     _E("Context is already initialized");
345   }
346
347   context_ = this;
348 }
349
350 AppCoreBase::~AppCoreBase() {
351   _I("");
352   context_ = nullptr;
353 }
354
355 AppCoreBase* AppCoreBase::GetContext() {
356   if (context_ == nullptr) {
357     _E("Context is not initialized.");
358     return nullptr;
359   }
360
361   return context_;
362 }
363
364 void AppCoreBase::Impl::ChangeLang() {
365   const char* lang = getenv("LANG");
366   if (lang == nullptr)
367     return;
368
369   InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
370 }
371
372 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
373   impl_->InvokeCallback(event, type);
374 }
375
376 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
377   impl_->InvokeCallback(event, type);
378 }
379
380 void AppCoreBase::Impl::OnFreezerSignal() {
381   if (!allowed_bg_ && suspended_state_) {
382     parent_->RemoveSuspendTimer();
383     InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
384         IEvent::Type::SUSPENDED_STATE_CHANGE);
385     suspended_state_ = false;
386     parent_->AddSuspendTimer();
387   }
388 }
389
390 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
391   if (data.value_count <= 0) {
392     _E("Failed to get sensor data");
393     return ROTATION_UNKNOWN;
394   }
395
396   int event = data.values[0];
397   switch (event) {
398   case AUTO_ROTATION_DEGREE_0:
399     return ROTATION_PORTRAIT_NORMAL;
400   case AUTO_ROTATION_DEGREE_90:
401     return ROTATION_LANDSCAPE_NORMAL;
402   case AUTO_ROTATION_DEGREE_180:
403     return ROTATION_PORTRAIT_REVERSE;
404   case AUTO_ROTATION_DEGREE_270:
405     return ROTATION_LANDSCAPE_REVERSE;
406   default:
407     return ROTATION_UNKNOWN;
408   }
409 }
410
411 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
412   if (__suspend_dbus_handler_initialized)
413     return;
414
415   if (__bus == nullptr) {
416     GError* err = nullptr;
417     __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
418     if (__bus == nullptr) {
419       _E("Failed to connect to the D-BUS daemon: %s", err ? err->message : "");
420       if (err)
421         g_error_free(err);
422
423       return;
424     }
425   }
426
427   __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
428     __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
429     RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
430     ReceiveSuspendSignalCb, data, nullptr);
431
432   if (__suspend_dbus_handler_initialized == 0) {
433     _E("g_dbus_connection_signal_subscribe() is failed.");
434     return;
435   }
436
437   _D("[__SUSPEND__] suspend signal initialized");
438 }
439
440 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
441   InitSuspendDbusHandler(data);
442   return G_SOURCE_REMOVE;
443 }
444
445 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
446   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
447   base->impl_->sid_ = 0;
448   base->impl_->ChangeLang();
449   return G_SOURCE_REMOVE;
450 }
451
452 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
453     const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
454     gpointer user_data) {
455   if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
456     gint pid = -1;
457     gint status = 0;
458     g_variant_get(parameters, "(ii)", &status, &pid);
459     if (pid == getpid() && status == 0) {
460       AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
461       base->impl_->OnFreezerSignal();
462     }
463   }
464 }
465
466 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
467   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
468   if (base->impl_->sid_) {
469     GLib::SourceRemove(base->impl_->sid_);
470     base->impl_->sid_ = 0;
471   }
472
473   char* val = vconf_keynode_get_str(key);
474   if (val == nullptr)
475     return;
476
477   base->impl_->UpdateLang();
478   base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
479 }
480
481 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
482   const char* name = vconf_keynode_get_name(key);
483   if (name == nullptr)
484     return;
485
486   if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
487       strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
488     return;
489
490   char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
491   if (val == nullptr)
492     return;
493   std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
494
495   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
496   base->impl_->UpdateRegion();
497   base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
498 }
499
500 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
501   int val = vconf_keynode_get_int(key);
502   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
503   base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
504   if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
505     malloc_trim(0);
506 }
507
508 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
509     void* user_data) {
510   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
511   if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
512     __rotation.charger_status = vconf_keynode_get_int(keynode);
513     if (__rotation.ref) {
514       if (__rotation.charger_status) {
515         base->impl_->InitRotation();
516       } else {
517         base->impl_->FiniRotation();
518       }
519     }
520
521     _D("charger status(%d)", __rotation.charger_status);
522   }
523 }
524
525 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
526   AppCoreBase::RotationState rm;
527   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
528
529   __rotation.lock = !vconf_keynode_get_bool(node);
530   if (__rotation.lock) {
531     _D("Rotation locked");
532     rm = ROTATION_PORTRAIT_NORMAL;
533   } else {
534     _D("Rotation unlocked");
535     sensor_data_t data;
536     bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
537     if (!r) {
538       _E("Failed to get sensor data");
539       return;
540     }
541
542     rm = base->impl_->GetRm(data);
543     if (rm == ROTATION_UNKNOWN) {
544       _E("Unknown mode");
545       return;
546     }
547   }
548
549   if (__rotation.rm == rm)
550     return;
551
552   _D("Rotation: %d -> %d", __rotation.rm, rm);
553   __rotation.rm = rm;
554   base->impl_->InvokeCallback(__rotation.rm,
555       IEvent::Type::DEVICE_ORIENTATION_CHANGED);
556 }
557
558 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
559     unsigned int event_type, sensor_data_t* data, void* user_data) {
560   if (data == nullptr)
561     return;
562
563   if (__rotation.lock)
564     return;
565
566   if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
567     return;
568
569   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
570   AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
571   if (rm == ROTATION_UNKNOWN) {
572     _E("Unknown mode");
573     return;
574   }
575
576   _D("Rotation: %d -> %d", __rotation.rm, rm);
577   __rotation.rm = rm;
578   base->impl_->InvokeCallback(__rotation.rm,
579       IEvent::Type::DEVICE_ORIENTATION_CHANGED);
580 }
581
582 void AppCoreBase::Impl::InitRotation() {
583   if (__rotation.initialized)
584     return;
585
586   sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
587   __rotation.conn = sensord_connect(sensor);
588   if (__rotation.conn < 0) {
589     _E("Failed to connect sensord");
590     return;
591   }
592
593   bool r = sensord_register_event(__rotation.conn,
594       AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
595       AutoRotationChangedCb, parent_);
596   if (!r) {
597     _E("Failed to register auto rotation change event");
598     sensord_disconnect(__rotation.conn);
599     return;
600   }
601
602   r = sensord_start(__rotation.conn, 0);
603   if (!r) {
604     _E("Failed to start sensord");
605     sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
606     sensord_disconnect(__rotation.conn);
607     return;
608   }
609
610   int lock = 0;
611   vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
612   vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
613       parent_);
614
615   __rotation.lock = !lock;
616   __rotation.initialized = true;
617 }
618
619 void AppCoreBase::Impl::FiniRotation() {
620   if (!__rotation.initialized)
621     return;
622
623   vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
624   sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
625   sensord_stop(__rotation.conn);
626   sensord_disconnect(__rotation.conn);
627
628   __rotation.lock = 0;
629   __rotation.initialized = false;
630 }
631
632 void AppCoreBase::Impl::VerifyLanguage() {
633   const char* env_lang = getenv("LANG");
634   if (env_lang == nullptr)
635     return;
636
637   char* lang = vconf_get_str(VCONFKEY_LANGSET);
638   if (lang == nullptr)
639     return;
640
641   std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
642
643   if (strcmp(env_lang, lang) != 0) {
644     _I("LANG(%s), LANGSET(%s)", env_lang, lang);
645     sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
646   }
647 }
648
649 void AppCoreBase::Impl::SetDefaultEvents() {
650   vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
651   int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
652       parent_);
653   if (r == 0) {
654     vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
655         parent_);
656   }
657
658   vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
659 }
660
661 void AppCoreBase::Impl::UnsetDefaultEvents() {
662   vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
663   int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
664   if (r == 0)
665     vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
666
667   vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
668 }
669
670 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
671   switch (type) {
672   case AUL_START:
673     _D("[APP %d]     AUL event: AUL_START", getpid());
674     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
675       std::string bg = b.GetString(AUL_K_ALLOWED_BG);
676       if (bg == "ALLOWED_BG") {
677         _D("[__SUSPEND__] allowed background");
678         impl_->allowed_bg_ = true;
679         RemoveSuspendTimer();
680       }
681     }
682
683     traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
684     if (impl_->core_delegator_)
685       impl_->core_delegator_->OnControl(std::move(b));
686     else
687       OnControl(std::move(b));
688     traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
689     break;
690   case AUL_RESUME:
691     _D("[APP %d]     AUL event: AUL_RESUME", getpid());
692     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
693       std::string bg = b.GetString(AUL_K_ALLOWED_BG);
694       if (bg == "ALLOWED_BG") {
695         _D("[__SUSPEND__] allowed background");
696         impl_->allowed_bg_ = true;
697         RemoveSuspendTimer();
698       }
699     }
700     break;
701   case AUL_TERMINATE:
702     _D("[APP %d]     AUL event: AUL_TERMINATE", getpid());
703     aul_status_update(STATUS_DYING);
704     if (!impl_->allowed_bg_)
705       RemoveSuspendTimer();
706
707     Exit();
708     break;
709   case AUL_TERMINATE_INST:
710   case AUL_TERMINATE_BG_INST:
711   case AUL_TERMINATE_BGAPP:
712     _D("[APP %d]     AUL event: %d", getpid(), type);
713     if (!impl_->allowed_bg_)
714       RemoveSuspendTimer();
715     break;
716   case AUL_WAKE:
717     _D("[APP %d]     AUL event: AUL_WAKE", getpid());
718     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
719       if (!impl_->allowed_bg_ && impl_->suspended_state_) {
720         RemoveSuspendTimer();
721         int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
722         impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
723         impl_->suspended_state_ = false;
724       }
725     }
726     break;
727   case AUL_SUSPEND:
728     _D("[APP %d]     AUL event: AUL_SUSPEND", getpid());
729     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
730       if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
731         RemoveSuspendTimer();
732         FlushMemory();
733       }
734     }
735     break;
736   case AUL_UPDATE_REQUESTED:
737     _D("[APP %d]     AUL event: AUL_UPDATE_REQUESTED", getpid());
738     impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
739     break;
740   default:
741     _D("[APP %d]     AUL event: %d", getpid(), type);
742     /* do nothing */
743     break;
744   }
745
746   return 0;
747 }
748
749 int AppCoreBase::OnCreate() {
750   int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
751         AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
752         if (base->impl_->core_delegator_) {
753           return base->impl_->core_delegator_->OnReceive(type,
754               b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
755         }
756         return base->OnReceive(type,
757             b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
758       }, this);
759   if (ret < 0 && ret != AUL_R_ECANCELED) {
760     _E("aul_launch_init() is failed. error(%d)", ret);
761     return -1;
762   }
763
764   ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
765   if (ret < 0) {
766     _E("aul_launch_argv_handler() is failed. error(%d)", ret);
767     return -1;
768   }
769
770   return 0;
771 }
772
773 int AppCoreBase::OnControl(tizen_base::Bundle b) {
774   return 0;
775 }
776
777 int AppCoreBase::OnTerminate() {
778   aul_finalize();
779   return 0;
780 }
781
782 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
783   impl_->core_delegator_ = delegator;
784 }
785
786 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
787   impl_->loop_delegator_ = delegator;
788 }
789
790 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
791   if (appid == nullptr)
792     return "";
793
794   /* com.vendor.name -> name */
795   const char* name_token = strrchr(appid, '.');
796   if (name_token == nullptr)
797     return appid;
798
799   name_token++;
800   return name_token;
801 }
802
803 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
804   const char* res_path = aul_get_app_resource_path();
805   if (res_path == nullptr) {
806     _E("Failed to get resource path");
807     return "";
808   }
809
810   return std::string(res_path) + PATH_LOCALE;
811 }
812
813 int AppCoreBase::OnSetI18n() {
814   char appid[PATH_MAX];
815   int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
816   if (ret < 0) {
817     _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
818     return -1;
819   }
820
821   std::string name = impl_->GetAppName(appid);
822   if (name.empty())
823     return -1;
824
825   std::string locale_dir = impl_->GetLocaleResourceDir();
826   if (locale_dir.empty())
827     return -1;
828
829   return SetI18n(move(name), move(locale_dir));
830 }
831
832 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
833   int val = vconf_keynode_get_int(key);
834   if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
835     AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
836     base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
837   }
838 }
839
840 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
841   if (!__rotation.ref)
842     return;
843
844   __rotation.ref--;
845   if (__rotation.ref == 0) {
846     FiniRotation();
847     if (feature_ & FEATURE_CHARGER_STATUS) {
848       vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
849           ChargerStatusChangedCb);
850     }
851   }
852 }
853
854 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
855   if (__rotation.ref == 0) {
856     if (feature_ & FEATURE_CHARGER_STATUS) {
857       vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
858       vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
859           ChargerStatusChangedCb, parent_);
860       if (__rotation.charger_status)
861         InitRotation();
862     } else {
863       InitRotation();
864     }
865   }
866
867   __rotation.ref++;
868 }
869
870 int AppCoreBase::OnSetEvent(IEvent::Type event) {
871   switch (event) {
872   case IEvent::Type::LOW_BATTERY:
873     vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
874         impl_->OnLowBatteryCb, this);
875     break;
876   case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
877     impl_->RegisterRotationChangedEvent();
878     break;
879   case IEvent::Type::SUSPENDED_STATE_CHANGE:
880     break;
881   default:
882     break;
883   }
884
885   return 0;
886 }
887
888 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
889   switch (event) {
890   case IEvent::Type::LOW_BATTERY:
891     vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
892         impl_->OnLowBatteryCb);
893     break;
894   case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
895     impl_->UnregisterRotationChangedEvent();
896     break;
897   case IEvent::Type::SUSPENDED_STATE_CHANGE:
898     break;
899   default:
900     break;
901   }
902
903   return 0;
904 }
905
906 int AppCoreBase::OnTrimMemory() {
907   int (*sqlite3_free_heap_memory)(int);
908
909   sqlite3_free_heap_memory = reinterpret_cast<
910       decltype(sqlite3_free_heap_memory)>(
911           dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
912   if (sqlite3_free_heap_memory)
913     sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
914
915   malloc_trim(0);
916   return 0;
917 }
918
919 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
920   bool found = false;
921   for (auto& ev : impl_->events_) {
922     if (ev->GetType() == event->GetType()) {
923       found = true;
924       break;
925     }
926   }
927
928   if (!found) {
929     if (impl_->core_delegator_)
930       impl_->core_delegator_->OnSetEvent(event->GetType());
931     else
932       OnSetEvent(event->GetType());
933   }
934
935   impl_->events_.push_back(move(event));
936 }
937
938 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
939   bool found = false;
940   impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
941     if (event.get() == ptr.get()) {
942       found = true;
943       return true;
944     }
945     return false;
946   });
947
948   return found;
949 }
950
951 void AppCoreBase::FlushMemory() {
952   if (impl_->core_delegator_)
953     impl_->core_delegator_->OnTrimMemory();
954   else
955     OnTrimMemory();
956
957   impl_->tid_ = 0;
958   if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
959     _D("[__SUSPEND__] flush case");
960     int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
961     impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
962     impl_->suspended_state_ = true;
963   }
964 }
965
966 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
967   if (!__rotation.ref)
968     throw std::runtime_error("invalid rotation state");
969
970   return __rotation.rm;
971 }
972
973 bool AppCoreBase::IsBgAllowed() {
974   return impl_->allowed_bg_;
975 }
976
977 bool AppCoreBase::IsSuspended() {
978   return impl_->suspended_state_;
979 }
980
981 void AppCoreBase::ToggleSuspendedState() {
982   impl_->suspended_state_ = !impl_->suspended_state_;
983 }
984
985 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
986     const std::string& lang) {
987   std::istringstream ss(lang);
988   std::list<std::string> li;
989   std::string token;
990
991   while (std::getline(ss, token, ':'))
992     li.push_back(token);
993
994   return li;
995 }
996
997 void AppCoreBase::Impl::AppendDefaultLangs(std::vector<std::string>& langs) {
998   langs.push_back("en_US");
999   langs.push_back("en_GB");
1000   langs.push_back("en");
1001 }
1002
1003 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
1004     const char* delim) {
1005   if (cstr == nullptr || delim == nullptr)
1006     return "";
1007
1008   auto str = std::string(cstr);
1009   auto idx = str.find(delim);
1010   return str.substr(0, idx);
1011 }
1012
1013 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
1014   if (locale_dir_.empty())
1015     return {};
1016
1017   DIR* dp = opendir(locale_dir_.c_str());
1018   if (dp == nullptr)
1019     return {};
1020
1021   std::map<std::string, std::set<std::string>> table;
1022   struct dirent *dentry;
1023   while ((dentry = readdir(dp)) != nullptr) {
1024     if (!strcmp(dentry->d_name, ".") ||
1025         !strcmp(dentry->d_name, ".."))
1026       continue;
1027
1028     std::string buf = locale_dir_ + "/" + dentry->d_name;
1029     struct stat stat_buf;
1030     int ret = stat(buf.c_str(), &stat_buf);
1031     if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
1032       continue;
1033
1034     std::string parent_lang = GetStringBefore(dentry->d_name, "_");
1035     if (parent_lang.empty()) {
1036       _E("Out of memory");
1037       break;
1038     }
1039
1040     table[parent_lang].insert(dentry->d_name);
1041   }
1042
1043   closedir(dp);
1044   return table;
1045 }
1046
1047 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
1048     std::vector<std::string>& langs,
1049     std::map<std::string, std::set<std::string>>& table) {
1050   if (lang.empty())
1051     return;
1052
1053   langs.push_back(lang);
1054   std::string extract_lang = GetStringBefore(lang.c_str(), ".");
1055   if (extract_lang.empty())
1056     return;
1057
1058   if (std::find(langs.begin(), langs.end(), extract_lang) != langs.end())
1059     return;
1060
1061   std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
1062   if (parent_lang.empty())
1063     return;
1064
1065   if (table.find(parent_lang) == table.end())
1066     return;
1067
1068   auto it = table[parent_lang].find(extract_lang);
1069   if (it != table[parent_lang].end()) {
1070     std::string value = *it;
1071     if (std::find(langs.begin(), langs.end(), value) == langs.end())
1072       langs.push_back(std::move(value));
1073
1074     table[parent_lang].erase(it);
1075     return;
1076   }
1077
1078   it = table[parent_lang].find(parent_lang);
1079   if (it != table[parent_lang].end()) {
1080     std::string value = *it;
1081     if (std::find(langs.begin(), langs.end(), value) == langs.end())
1082       langs.push_back(std::move(value));
1083
1084     table[parent_lang].erase(parent_lang);
1085     return;
1086   }
1087
1088   if (!table[parent_lang].empty()) {
1089     auto i = table[parent_lang].begin();
1090     std::string value = *i;
1091     if (std::find(langs.begin(), langs.end(), value) == langs.end())
1092       langs.push_back(std::move(value));
1093
1094     table[parent_lang].erase(i);
1095   }
1096 }
1097
1098 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
1099   std::list<std::string> l = SplitLanguage(lang);
1100   if (l.empty())
1101     return "";
1102
1103   auto table = GetLangTable();
1104   if (table.empty())
1105     return "";
1106
1107   std::vector<std::string> langs;
1108   for (auto& i : l)
1109     AppendLangs(i, langs, table);
1110
1111   AppendDefaultLangs(langs);
1112   std::string ret;
1113   for (auto& i : langs) {
1114     if (ret.empty())
1115       ret = i;
1116     else
1117       ret += ":" + i;
1118   }
1119
1120   return ret;
1121 }
1122
1123 void AppCoreBase::Impl::UpdateLang() {
1124   char* lang = vconf_get_str(VCONFKEY_LANGSET);
1125   if (lang == nullptr)
1126     return;
1127
1128   std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1129   std::string language = GetLanguage(lang);
1130   if (!language.empty()) {
1131     _D("*****language(%s)", language.c_str());
1132     setenv("LANGUAGE", language.c_str(), 1);
1133   } else {
1134     setenv("LANGUAGE", lang, 1);
1135   }
1136   setenv("LANG", lang, 1);
1137   setenv("LC_MESSAGES", lang, 1);
1138   setenv("LC_ALL", lang, 1);
1139   char* r = setlocale(LC_ALL, "");
1140   if (r == nullptr) {
1141     r = setlocale(LC_ALL, "en_US.UTF-8");
1142     if (r != nullptr) {
1143       _D("*****appcore setlocale=%s\n", r);
1144     } else {
1145       _D("*****appcore setlocale=\"C\"");
1146       setenv("LC_ALL", "C", 1);
1147       r = setlocale(LC_ALL, "");
1148       if (r == nullptr)
1149         _E("failed to setlocale");
1150     }
1151   }
1152 }
1153
1154 void AppCoreBase::Impl::UpdateRegion() {
1155   char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1156   if (region == nullptr)
1157     return;
1158
1159   std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1160   setenv("LC_CTYPE", region, 1);
1161   setenv("LC_NUMERIC", region, 1);
1162   setenv("LC_TIME", region, 1);
1163   setenv("LC_COLLATE", region, 1);
1164   setenv("LC_MONETARY", region, 1);
1165   setenv("LC_PAPER", region, 1);
1166   setenv("LC_NAME", region, 1);
1167   setenv("LC_ADDRESS", region, 1);
1168   setenv("LC_TELEPHONE", region, 1);
1169   setenv("LC_MEASUREMENT", region, 1);
1170   setenv("LC_IDENTIFICATION", region, 1);
1171   char* r = setlocale(LC_ALL, "");
1172   if (r != nullptr) {
1173     _D("*****appcore setlocale=%s\n", r);
1174   } else {
1175     _D("*****appcore setlocale=\"C\"");
1176     setenv("LC_ALL", "C", 1);
1177     r = setlocale(LC_ALL, "");
1178     if (r == nullptr)
1179       _E("failed to setlocale");
1180   }
1181 }
1182
1183 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1184   if (domain_name.empty()) {
1185     errno = EINVAL;
1186     return -1;
1187   }
1188
1189   if (!dir_name.empty())
1190     impl_->locale_dir_ = dir_name;
1191
1192   impl_->UpdateLang();
1193   impl_->UpdateRegion();
1194
1195   char* r = setlocale(LC_ALL, "");
1196   /* if locale is not set properly, try to set "en_US" again */
1197   if (r == nullptr) {
1198     r = setlocale(LC_ALL, "en_US.UTF-8");
1199     if (r == nullptr) {
1200       _E("appcore: setlocale() error");
1201       _D("*****appcore setlocale=\"C\"");
1202       setenv("LC_ALL", "C", 1);
1203       r = setlocale(LC_ALL, "");
1204       if (r == nullptr)
1205         _E("failed to setlocale");
1206     }
1207   }
1208
1209   if (r != nullptr)
1210     _D("*****appcore setlocale=%s\n", r);
1211
1212   r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1213   if (r == nullptr)
1214     _E("appcore: bindtextdomain() error");
1215
1216   r = textdomain(domain_name.c_str());
1217   if (r == nullptr)
1218     _E("appcore: textdomain() error");
1219
1220   return 0;
1221 }
1222
1223 void AppCoreBase::Exit() {
1224   aul_status_update(STATUS_DYING);
1225   if (impl_->loop_delegator_)
1226     impl_->loop_delegator_->OnLoopExit();
1227   else
1228     OnLoopExit();
1229 }
1230
1231 void AppCoreBase::AddSuspendTimer() {
1232   impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1233         AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1234         base->FlushMemory();
1235         return FALSE;
1236       }, this);
1237 }
1238
1239 void AppCoreBase::RemoveSuspendTimer() {
1240   if (impl_->tid_ > 0) {
1241     GLib::SourceRemove(impl_->tid_);
1242     impl_->tid_ = 0;
1243   }
1244 }
1245
1246 void AppCoreBase::SetDisplayState(DisplayState state) {
1247   __display_state = state;
1248 }
1249
1250 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1251   return __display_state;
1252 }
1253
1254 int AppCoreBase::EnableWatchdog() {
1255   _I("[__APPCORE_WATCHDOG__] enable");
1256   return aul_watchdog_enable();
1257 }
1258
1259 int AppCoreBase::DisableWatchdog() {
1260   _I("[__APPCORE_WATCHDOG__] disable");
1261   return aul_watchdog_disable();
1262 }
1263
1264 int AppCoreBase::KickWatchdog() {
1265   _I("[__APPCORE_WATCHDOG__] kick");
1266   return aul_watchdog_kick();
1267 }
1268
1269 void AppCoreBase::Run(int argc, char** argv) {
1270   Init(argc, argv);
1271   Fini();
1272 }
1273
1274 void AppCoreBase::Init(int argc, char** argv) {
1275   impl_->tid_ = 0;
1276   impl_->suspended_state_ = false;
1277   impl_->allowed_bg_ = false;
1278   impl_->argc_ = argc;
1279   impl_->argv_ = argv;
1280   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1281   sigterm_handler.Restore();
1282   if (impl_->loop_delegator_)
1283     impl_->loop_delegator_->OnLoopInit(argc, argv);
1284   else
1285     OnLoopInit(argc, argv);
1286
1287   impl_->signal_handler_source_ = g_unix_signal_add(SIGTERM,
1288       [](gpointer data) -> gboolean {
1289         _W("sigterm handler");
1290         if (context_ != nullptr) {
1291           context_->Exit();
1292           context_->impl_->signal_handler_source_ = 0;
1293         }
1294
1295         return G_SOURCE_REMOVE;
1296       }, nullptr);
1297
1298   if (impl_->signal_handler_source_ == 0)
1299     _E("Failed to add sigterm handler.");
1300
1301   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1302
1303   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:PLUGIN_INIT");
1304   impl_->PluginInit(argc, argv);
1305   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1306
1307   if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1308     GLib::IdleAdd(Impl::InitSuspendCb, this);
1309
1310   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1311   if (!impl_->dirty_) {
1312     impl_->dirty_ = true;
1313
1314     for (auto& e : impl_->events_) {
1315       if (impl_->core_delegator_)
1316         impl_->core_delegator_->OnSetEvent(e->GetType());
1317       else
1318         OnSetEvent(e->GetType());
1319     }
1320   }
1321   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1322
1323   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1324   impl_->VerifyLanguage();
1325   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1326
1327   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1328   impl_->SetDefaultEvents();
1329   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1330
1331   if (impl_->core_delegator_)
1332     impl_->core_delegator_->OnSetI18n();
1333   else
1334     OnSetI18n();
1335
1336   aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1337
1338   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1339   int create = 0;
1340   if (impl_->core_delegator_)
1341     create = impl_->core_delegator_->OnCreate();
1342   else
1343     create = OnCreate();
1344   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1345
1346   aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1347   if (create < 0)
1348     return;
1349
1350   if (impl_->loop_delegator_)
1351     impl_->loop_delegator_->OnLoopRun();
1352   else
1353     OnLoopRun();
1354 }
1355
1356 void AppCoreBase::Fini() {
1357   if (impl_->signal_handler_source_) {
1358     g_source_remove(impl_->signal_handler_source_);
1359     impl_->signal_handler_source_ = 0;
1360   }
1361
1362   Dispose();
1363 }
1364
1365 void AppCoreBase::Dispose() {
1366   aul_status_update(STATUS_DYING);
1367   DisableWatchdog();
1368   aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1369
1370   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1371   if (impl_->core_delegator_)
1372     impl_->core_delegator_->OnTerminate();
1373   else
1374     OnTerminate();
1375   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1376
1377   for (auto& e : impl_->events_) {
1378     if (impl_->core_delegator_)
1379       impl_->core_delegator_->OnUnsetEvent(e->GetType());
1380     else
1381       OnUnsetEvent(e->GetType());
1382   }
1383
1384   impl_->UnsetDefaultEvents();
1385   if (impl_->sid_) {
1386     GLib::SourceRemove(impl_->sid_);
1387     impl_->sid_ = 0;
1388   }
1389
1390   RemoveSuspendTimer();
1391   impl_->PluginFini();
1392   impl_->dirty_ = false;
1393   if (impl_->loop_delegator_)
1394     impl_->loop_delegator_->OnLoopFinish();
1395   else
1396     OnLoopFinish();
1397 }
1398
1399 void AppCoreBase::SetFeature(int feature) {
1400   impl_->feature_ = feature;
1401 }
1402
1403 int AppCoreBase::GetFeature() const {
1404   return impl_->feature_;
1405 }
1406
1407 void AppCoreBase::Impl::PluginInit(int argc, char** argv) {
1408   plugin_.reset(AppCorePlugin::Load());
1409   if (!plugin_)
1410     return;
1411
1412   plugin_->Init(argc, argv);
1413 }
1414
1415 void AppCoreBase::Impl::PluginFini() {
1416   if (!plugin_)
1417     return;
1418
1419   plugin_->Fini();
1420 }
1421
1422 }  // namespace tizen_cpp