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