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