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