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