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