2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "app-core-cpp/app_core_base.hh"
20 #include <aul_app_lifecycle.h>
21 #include <aul_watchdog.h>
22 #include <bundle_internal.h>
27 #include <glib-unix.h>
30 #include <linux/limits.h>
33 #include <sensor_internal.h>
38 #include <sys/types.h>
39 #include <system_info.h>
54 #include "app-core-cpp/app_core_plugin_private.hh"
55 #include "app-core-cpp/sigterm_handler_private.hh"
56 #include "common/glib_private.hh"
57 #include "common/log_private.hh"
59 #define SIGRTANR (SIGRTMIN + 3)
61 #define _ERR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
63 extern "C" void aul_finalize();
66 AppCoreBase* AppCoreBase::context_ = nullptr;
70 constexpr const int BACKTRACE_BUFFER_SIZE = 128;
72 void PrintBacktrace() {
73 char* buffer[BACKTRACE_BUFFER_SIZE];
74 int nptrs = backtrace(reinterpret_cast<void**>(buffer),
75 BACKTRACE_BUFFER_SIZE);
76 _ERR("backtrace() returned %d addresses", nptrs - 4);
78 // To print numbers, we use backtrace_symbols() instead of backtrace_symbols_fd().
79 // If there is an issues related to the memory, we cannot use backtrace_symbols().
80 // backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
81 char** strings = backtrace_symbols(reinterpret_cast<void**>(buffer), nptrs);
82 if (strings == nullptr) {
83 perror("backtrace_symbols");
88 for (int i = 4; i < nptrs; ++i) {
89 dladdr(buffer[i], &info);
91 i - 4, info.dli_sname ? info.dli_sname : "?", strings[i]);
99 on_exit(OnExit, this);
103 static void OnExit(int status, void *user_data) {
109 _ERR("%s(%d) abort()", __FUNCTION__, __LINE__);
114 ExitHandler exit_handler;
119 struct sigaction action;
120 memset(&action, '\0', sizeof(action));
121 sigemptyset(&action.sa_mask);
122 action.sa_flags = SA_RESTART;
123 action.sa_handler = SignalHandler;
125 if (sigaction(SIGRTANR, &action, &old_action_) != 0)
126 _E("sigaction() is failed. errno(%d)", errno);
130 if (sigaction(SIGRTANR, &old_action_, nullptr) != 0)
131 _W("sigaction() is failed. errno(%d)", errno);
135 static void SignalHandler(int signo) {
136 static unsigned int count;
137 _ERR("===================================================================");
138 _ERR("=================== Application Not Responding ====================");
140 _ERR("============== Application did not respond %d times ===============",
142 _ERR("===================================================================");
146 struct sigaction old_action_;
149 AnrMonitor anr_monitor;
150 internal::SigtermHandler sigterm_handler;
161 TizenProfile TizenProfileGet() {
162 static TizenProfile profile = TizenProfile::Unknown;
163 if (__builtin_expect(profile != TizenProfile::Unknown, 1))
166 char* profile_name = nullptr;
167 system_info_get_platform_string("http://tizen.org/feature/profile",
169 if (profile_name == nullptr)
172 switch (*profile_name) {
175 profile = TizenProfile::Mobile;
179 profile = TizenProfile::Wearable;
183 profile = TizenProfile::Tv;
187 profile = TizenProfile::Ivi;
190 profile = TizenProfile::Common;
198 constexpr const char PATH_LOCALE[] = "locale";
199 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
200 constexpr const char RESOURCED_FREEZER_PATH[] =
201 "/Org/Tizen/ResourceD/Freezer";
202 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
203 "org.tizen.resourced.freezer";
204 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
211 tizen_cpp::AppCoreBase::RotationState rm;
217 GDBusConnection* __bus;
218 guint __suspend_dbus_handler_initialized;
219 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
223 class AppCoreBase::EventBase::Impl {
225 friend class AppCoreBase;
226 Type type_ = IEvent::Type::START;
227 std::string str_val_;
231 class AppCoreBase::Impl {
233 explicit Impl(AppCoreBase* parent) : parent_(parent) {
234 if (TizenProfileGet() & TizenProfile::Wearable)
235 feature_ |= FEATURE_CHARGER_STATUS;
236 if (!(TizenProfileGet() & TizenProfile::Tv))
237 feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
241 void UnregisterRotationChangedEvent();
242 void RegisterRotationChangedEvent();
243 std::string GetAppName(const char* appid);
244 std::string GetLocaleResourceDir();
247 std::list<std::string> SplitLanguage(const std::string& lang);
248 std::string GetLanguage(std::string lang);
249 void AppendDefaultLangs(std::vector<std::string>& lang_set);
250 std::string GetStringBefore(const char* str, const char* delim);
251 std::map<std::string, std::set<std::string>> GetLangTable();
252 void AppendLangs(const std::string& lang, std::vector<std::string>& lang_set,
253 std::map<std::string, std::set<std::string>>& table);
255 void OnFreezerSignal();
258 void InvokeCallback(T event, IEvent::Type type) {
259 for (auto& i : events_) {
260 if (i->GetType() != type)
263 if (i->GetVal(event) != event ||
264 type == IEvent::Type::START ||
265 type == IEvent::Type::UPDATE_REQUESTED) {
272 static void InitSuspendDbusHandler(gpointer data);
273 static gboolean InitSuspendCb(gpointer data);
274 static gboolean InvokeLangChangeCb(gpointer data);
275 static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
276 const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
277 static void OnLowBatteryCb(keynode_t* key, void* data);
278 static void LockCb(keynode_t* node, void* user_data);
279 static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
280 sensor_data_t* data, void* user_data);
281 static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
282 static void LanguageChangeCb(keynode_t* key, void* data);
283 static void RegionChangeCb(keynode_t* key, void* data);
284 static void LowMemoryCb(keynode_t* key, void* data);
287 RotationState GetRm(sensor_data_t data);
288 void VerifyLanguage();
289 void SetDefaultEvents();
290 void UnsetDefaultEvents();
291 void PluginInit(int argc, char** argv);
295 friend class AppCoreBase;
296 AppCoreBase* parent_ = nullptr;
299 char** argv_ = nullptr;
300 bool suspended_state_ = false;
301 bool allowed_bg_ = false;
303 unsigned int tid_ = 0;
304 std::list<std::shared_ptr<EventBase>> events_;
305 std::string locale_dir_;
308 IAppCore* core_delegator_ = nullptr;
309 IMainLoop* loop_delegator_ = nullptr;
310 guint signal_handler_source_ = 0;
311 std::unique_ptr<AppCorePlugin> plugin_;
314 AppCoreBase::EventBase::EventBase(Type type)
315 : impl_(std::make_unique<EventBase::Impl>()) {
319 AppCoreBase::EventBase::~EventBase() = default;
321 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
325 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
326 return impl_->str_val_;
329 int AppCoreBase::EventBase::GetVal(int cur) const {
333 void AppCoreBase::EventBase::SetVal(std::string val) {
334 impl_->str_val_ = std::move(val);
337 void AppCoreBase::EventBase::SetVal(int val) {
338 impl_->val_ = std::move(val);
341 AppCoreBase::AppCoreBase()
342 : impl_(std::make_unique<AppCoreBase::Impl>(this)) {
343 if (context_ != nullptr) {
344 _E("Context is already initialized");
350 AppCoreBase::~AppCoreBase() {
355 AppCoreBase* AppCoreBase::GetContext() {
356 if (context_ == nullptr) {
357 _E("Context is not initialized.");
364 void AppCoreBase::Impl::ChangeLang() {
365 const char* lang = getenv("LANG");
369 InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
372 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
373 impl_->InvokeCallback(event, type);
376 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
377 impl_->InvokeCallback(event, type);
380 void AppCoreBase::Impl::OnFreezerSignal() {
381 if (!allowed_bg_ && suspended_state_) {
382 parent_->RemoveSuspendTimer();
383 InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
384 IEvent::Type::SUSPENDED_STATE_CHANGE);
385 suspended_state_ = false;
386 parent_->AddSuspendTimer();
390 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
391 if (data.value_count <= 0) {
392 _E("Failed to get sensor data");
393 return ROTATION_UNKNOWN;
396 int event = data.values[0];
398 case AUTO_ROTATION_DEGREE_0:
399 return ROTATION_PORTRAIT_NORMAL;
400 case AUTO_ROTATION_DEGREE_90:
401 return ROTATION_LANDSCAPE_NORMAL;
402 case AUTO_ROTATION_DEGREE_180:
403 return ROTATION_PORTRAIT_REVERSE;
404 case AUTO_ROTATION_DEGREE_270:
405 return ROTATION_LANDSCAPE_REVERSE;
407 return ROTATION_UNKNOWN;
411 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
412 if (__suspend_dbus_handler_initialized)
415 if (__bus == nullptr) {
416 GError* err = nullptr;
417 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
418 if (__bus == nullptr) {
419 _E("Failed to connect to the D-BUS daemon: %s", err ? err->message : "");
427 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
428 __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
429 RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
430 ReceiveSuspendSignalCb, data, nullptr);
432 if (__suspend_dbus_handler_initialized == 0) {
433 _E("g_dbus_connection_signal_subscribe() is failed.");
437 _D("[__SUSPEND__] suspend signal initialized");
440 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
441 InitSuspendDbusHandler(data);
442 return G_SOURCE_REMOVE;
445 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
446 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
447 base->impl_->sid_ = 0;
448 base->impl_->ChangeLang();
449 return G_SOURCE_REMOVE;
452 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
453 const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
454 gpointer user_data) {
455 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
458 g_variant_get(parameters, "(ii)", &status, &pid);
459 if (pid == getpid() && status == 0) {
460 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
461 base->impl_->OnFreezerSignal();
466 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
467 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
468 if (base->impl_->sid_) {
469 GLib::SourceRemove(base->impl_->sid_);
470 base->impl_->sid_ = 0;
473 char* val = vconf_keynode_get_str(key);
477 base->impl_->UpdateLang();
478 base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
481 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
482 const char* name = vconf_keynode_get_name(key);
486 if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
487 strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
490 char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
493 std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
495 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
496 base->impl_->UpdateRegion();
497 base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
500 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
501 int val = vconf_keynode_get_int(key);
502 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
503 base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
504 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
508 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
510 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
511 if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
512 __rotation.charger_status = vconf_keynode_get_int(keynode);
513 if (__rotation.ref) {
514 if (__rotation.charger_status) {
515 base->impl_->InitRotation();
517 base->impl_->FiniRotation();
521 _D("charger status(%d)", __rotation.charger_status);
525 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
526 AppCoreBase::RotationState rm;
527 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
529 __rotation.lock = !vconf_keynode_get_bool(node);
530 if (__rotation.lock) {
531 _D("Rotation locked");
532 rm = ROTATION_PORTRAIT_NORMAL;
534 _D("Rotation unlocked");
536 bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
538 _E("Failed to get sensor data");
542 rm = base->impl_->GetRm(data);
543 if (rm == ROTATION_UNKNOWN) {
549 if (__rotation.rm == rm)
552 _D("Rotation: %d -> %d", __rotation.rm, rm);
554 base->impl_->InvokeCallback(__rotation.rm,
555 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
558 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
559 unsigned int event_type, sensor_data_t* data, void* user_data) {
566 if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
569 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
570 AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
571 if (rm == ROTATION_UNKNOWN) {
576 _D("Rotation: %d -> %d", __rotation.rm, rm);
578 base->impl_->InvokeCallback(__rotation.rm,
579 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
582 void AppCoreBase::Impl::InitRotation() {
583 if (__rotation.initialized)
586 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
587 __rotation.conn = sensord_connect(sensor);
588 if (__rotation.conn < 0) {
589 _E("Failed to connect sensord");
593 bool r = sensord_register_event(__rotation.conn,
594 AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
595 AutoRotationChangedCb, parent_);
597 _E("Failed to register auto rotation change event");
598 sensord_disconnect(__rotation.conn);
602 r = sensord_start(__rotation.conn, 0);
604 _E("Failed to start sensord");
605 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
606 sensord_disconnect(__rotation.conn);
611 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
612 vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
615 __rotation.lock = !lock;
616 __rotation.initialized = true;
619 void AppCoreBase::Impl::FiniRotation() {
620 if (!__rotation.initialized)
623 vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
624 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
625 sensord_stop(__rotation.conn);
626 sensord_disconnect(__rotation.conn);
629 __rotation.initialized = false;
632 void AppCoreBase::Impl::VerifyLanguage() {
633 const char* env_lang = getenv("LANG");
634 if (env_lang == nullptr)
637 char* lang = vconf_get_str(VCONFKEY_LANGSET);
641 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
643 if (strcmp(env_lang, lang) != 0) {
644 _I("LANG(%s), LANGSET(%s)", env_lang, lang);
645 sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
649 void AppCoreBase::Impl::SetDefaultEvents() {
650 vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
651 int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
654 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
658 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
661 void AppCoreBase::Impl::UnsetDefaultEvents() {
662 vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
663 int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
665 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
667 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
670 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
673 _D("[APP %d] AUL event: AUL_START", getpid());
674 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
675 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
676 if (bg == "ALLOWED_BG") {
677 _D("[__SUSPEND__] allowed background");
678 impl_->allowed_bg_ = true;
679 RemoveSuspendTimer();
683 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
684 if (impl_->core_delegator_)
685 impl_->core_delegator_->OnControl(std::move(b));
687 OnControl(std::move(b));
688 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
691 _D("[APP %d] AUL event: AUL_RESUME", getpid());
692 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
693 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
694 if (bg == "ALLOWED_BG") {
695 _D("[__SUSPEND__] allowed background");
696 impl_->allowed_bg_ = true;
697 RemoveSuspendTimer();
702 _D("[APP %d] AUL event: AUL_TERMINATE", getpid());
703 aul_status_update(STATUS_DYING);
704 if (!impl_->allowed_bg_)
705 RemoveSuspendTimer();
709 case AUL_TERMINATE_INST:
710 case AUL_TERMINATE_BG_INST:
711 case AUL_TERMINATE_BGAPP:
712 _D("[APP %d] AUL event: %d", getpid(), type);
713 if (!impl_->allowed_bg_)
714 RemoveSuspendTimer();
717 _D("[APP %d] AUL event: AUL_WAKE", getpid());
718 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
719 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
720 RemoveSuspendTimer();
721 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
722 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
723 impl_->suspended_state_ = false;
728 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
729 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
730 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
731 RemoveSuspendTimer();
736 case AUL_UPDATE_REQUESTED:
737 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
738 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
741 _D("[APP %d] AUL event: %d", getpid(), type);
749 int AppCoreBase::OnCreate() {
750 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
751 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
752 if (base->impl_->core_delegator_) {
753 return base->impl_->core_delegator_->OnReceive(type,
754 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
756 return base->OnReceive(type,
757 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
759 if (ret < 0 && ret != AUL_R_ECANCELED) {
760 _E("aul_launch_init() is failed. error(%d)", ret);
764 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
766 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
773 int AppCoreBase::OnControl(tizen_base::Bundle b) {
777 int AppCoreBase::OnTerminate() {
782 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
783 impl_->core_delegator_ = delegator;
786 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
787 impl_->loop_delegator_ = delegator;
790 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
791 if (appid == nullptr)
794 /* com.vendor.name -> name */
795 const char* name_token = strrchr(appid, '.');
796 if (name_token == nullptr)
803 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
804 const char* res_path = aul_get_app_resource_path();
805 if (res_path == nullptr) {
806 _E("Failed to get resource path");
810 return std::string(res_path) + PATH_LOCALE;
813 int AppCoreBase::OnSetI18n() {
814 char appid[PATH_MAX];
815 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
817 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
821 std::string name = impl_->GetAppName(appid);
825 std::string locale_dir = impl_->GetLocaleResourceDir();
826 if (locale_dir.empty())
829 return SetI18n(move(name), move(locale_dir));
832 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
833 int val = vconf_keynode_get_int(key);
834 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
835 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
836 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
840 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
845 if (__rotation.ref == 0) {
847 if (feature_ & FEATURE_CHARGER_STATUS) {
848 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
849 ChargerStatusChangedCb);
854 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
855 if (__rotation.ref == 0) {
856 if (feature_ & FEATURE_CHARGER_STATUS) {
857 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
858 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
859 ChargerStatusChangedCb, parent_);
860 if (__rotation.charger_status)
870 int AppCoreBase::OnSetEvent(IEvent::Type event) {
872 case IEvent::Type::LOW_BATTERY:
873 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
874 impl_->OnLowBatteryCb, this);
876 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
877 impl_->RegisterRotationChangedEvent();
879 case IEvent::Type::SUSPENDED_STATE_CHANGE:
888 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
890 case IEvent::Type::LOW_BATTERY:
891 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
892 impl_->OnLowBatteryCb);
894 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
895 impl_->UnregisterRotationChangedEvent();
897 case IEvent::Type::SUSPENDED_STATE_CHANGE:
906 int AppCoreBase::OnTrimMemory() {
907 int (*sqlite3_free_heap_memory)(int);
909 sqlite3_free_heap_memory = reinterpret_cast<
910 decltype(sqlite3_free_heap_memory)>(
911 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
912 if (sqlite3_free_heap_memory)
913 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
919 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
921 for (auto& ev : impl_->events_) {
922 if (ev->GetType() == event->GetType()) {
929 if (impl_->core_delegator_)
930 impl_->core_delegator_->OnSetEvent(event->GetType());
932 OnSetEvent(event->GetType());
935 impl_->events_.push_back(move(event));
938 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
940 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
941 if (event.get() == ptr.get()) {
951 void AppCoreBase::FlushMemory() {
952 if (impl_->core_delegator_)
953 impl_->core_delegator_->OnTrimMemory();
958 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
959 _D("[__SUSPEND__] flush case");
960 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
961 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
962 impl_->suspended_state_ = true;
966 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
968 throw std::runtime_error("invalid rotation state");
970 return __rotation.rm;
973 bool AppCoreBase::IsBgAllowed() {
974 return impl_->allowed_bg_;
977 bool AppCoreBase::IsSuspended() {
978 return impl_->suspended_state_;
981 void AppCoreBase::ToggleSuspendedState() {
982 impl_->suspended_state_ = !impl_->suspended_state_;
985 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
986 const std::string& lang) {
987 std::istringstream ss(lang);
988 std::list<std::string> li;
991 while (std::getline(ss, token, ':'))
997 void AppCoreBase::Impl::AppendDefaultLangs(std::vector<std::string>& langs) {
998 langs.push_back("en_US");
999 langs.push_back("en_GB");
1000 langs.push_back("en");
1003 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
1004 const char* delim) {
1005 if (cstr == nullptr || delim == nullptr)
1008 auto str = std::string(cstr);
1009 auto idx = str.find(delim);
1010 return str.substr(0, idx);
1013 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
1014 if (locale_dir_.empty())
1017 DIR* dp = opendir(locale_dir_.c_str());
1021 std::map<std::string, std::set<std::string>> table;
1022 struct dirent *dentry;
1023 while ((dentry = readdir(dp)) != nullptr) {
1024 if (!strcmp(dentry->d_name, ".") ||
1025 !strcmp(dentry->d_name, ".."))
1028 std::string buf = locale_dir_ + "/" + dentry->d_name;
1029 struct stat stat_buf;
1030 int ret = stat(buf.c_str(), &stat_buf);
1031 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
1034 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
1035 if (parent_lang.empty()) {
1036 _E("Out of memory");
1040 table[parent_lang].insert(dentry->d_name);
1047 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
1048 std::vector<std::string>& langs,
1049 std::map<std::string, std::set<std::string>>& table) {
1053 langs.push_back(lang);
1054 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
1055 if (extract_lang.empty())
1058 if (std::find(langs.begin(), langs.end(), extract_lang) != langs.end())
1061 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
1062 if (parent_lang.empty())
1065 if (table.find(parent_lang) == table.end())
1068 auto it = table[parent_lang].find(extract_lang);
1069 if (it != table[parent_lang].end()) {
1070 std::string value = *it;
1071 if (std::find(langs.begin(), langs.end(), value) == langs.end())
1072 langs.push_back(std::move(value));
1074 table[parent_lang].erase(it);
1078 it = table[parent_lang].find(parent_lang);
1079 if (it != table[parent_lang].end()) {
1080 std::string value = *it;
1081 if (std::find(langs.begin(), langs.end(), value) == langs.end())
1082 langs.push_back(std::move(value));
1084 table[parent_lang].erase(parent_lang);
1088 if (!table[parent_lang].empty()) {
1089 auto i = table[parent_lang].begin();
1090 std::string value = *i;
1091 if (std::find(langs.begin(), langs.end(), value) == langs.end())
1092 langs.push_back(std::move(value));
1094 table[parent_lang].erase(i);
1098 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
1099 std::list<std::string> l = SplitLanguage(lang);
1103 auto table = GetLangTable();
1107 std::vector<std::string> langs;
1109 AppendLangs(i, langs, table);
1111 AppendDefaultLangs(langs);
1113 for (auto& i : langs) {
1123 void AppCoreBase::Impl::UpdateLang() {
1124 char* lang = vconf_get_str(VCONFKEY_LANGSET);
1125 if (lang == nullptr)
1128 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1129 std::string language = GetLanguage(lang);
1130 if (!language.empty()) {
1131 _D("*****language(%s)", language.c_str());
1132 setenv("LANGUAGE", language.c_str(), 1);
1134 setenv("LANGUAGE", lang, 1);
1136 setenv("LANG", lang, 1);
1137 setenv("LC_MESSAGES", lang, 1);
1138 setenv("LC_ALL", lang, 1);
1139 char* r = setlocale(LC_ALL, "");
1141 r = setlocale(LC_ALL, "en_US.UTF-8");
1143 _D("*****appcore setlocale=%s\n", r);
1145 _D("*****appcore setlocale=\"C\"");
1146 setenv("LC_ALL", "C", 1);
1147 r = setlocale(LC_ALL, "");
1149 _E("failed to setlocale");
1154 void AppCoreBase::Impl::UpdateRegion() {
1155 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1156 if (region == nullptr)
1159 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1160 setenv("LC_CTYPE", region, 1);
1161 setenv("LC_NUMERIC", region, 1);
1162 setenv("LC_TIME", region, 1);
1163 setenv("LC_COLLATE", region, 1);
1164 setenv("LC_MONETARY", region, 1);
1165 setenv("LC_PAPER", region, 1);
1166 setenv("LC_NAME", region, 1);
1167 setenv("LC_ADDRESS", region, 1);
1168 setenv("LC_TELEPHONE", region, 1);
1169 setenv("LC_MEASUREMENT", region, 1);
1170 setenv("LC_IDENTIFICATION", region, 1);
1171 char* r = setlocale(LC_ALL, "");
1173 _D("*****appcore setlocale=%s\n", r);
1175 _D("*****appcore setlocale=\"C\"");
1176 setenv("LC_ALL", "C", 1);
1177 r = setlocale(LC_ALL, "");
1179 _E("failed to setlocale");
1183 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1184 if (domain_name.empty()) {
1189 if (!dir_name.empty())
1190 impl_->locale_dir_ = dir_name;
1192 impl_->UpdateLang();
1193 impl_->UpdateRegion();
1195 char* r = setlocale(LC_ALL, "");
1196 /* if locale is not set properly, try to set "en_US" again */
1198 r = setlocale(LC_ALL, "en_US.UTF-8");
1200 _E("appcore: setlocale() error");
1201 _D("*****appcore setlocale=\"C\"");
1202 setenv("LC_ALL", "C", 1);
1203 r = setlocale(LC_ALL, "");
1205 _E("failed to setlocale");
1210 _D("*****appcore setlocale=%s\n", r);
1212 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1214 _E("appcore: bindtextdomain() error");
1216 r = textdomain(domain_name.c_str());
1218 _E("appcore: textdomain() error");
1223 void AppCoreBase::Exit() {
1224 aul_status_update(STATUS_DYING);
1225 if (impl_->loop_delegator_)
1226 impl_->loop_delegator_->OnLoopExit();
1231 void AppCoreBase::AddSuspendTimer() {
1232 impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1233 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1234 base->FlushMemory();
1239 void AppCoreBase::RemoveSuspendTimer() {
1240 if (impl_->tid_ > 0) {
1241 GLib::SourceRemove(impl_->tid_);
1246 void AppCoreBase::SetDisplayState(DisplayState state) {
1247 __display_state = state;
1250 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1251 return __display_state;
1254 int AppCoreBase::EnableWatchdog() {
1255 _I("[__APPCORE_WATCHDOG__] enable");
1256 return aul_watchdog_enable();
1259 int AppCoreBase::DisableWatchdog() {
1260 _I("[__APPCORE_WATCHDOG__] disable");
1261 return aul_watchdog_disable();
1264 int AppCoreBase::KickWatchdog() {
1265 _I("[__APPCORE_WATCHDOG__] kick");
1266 return aul_watchdog_kick();
1269 void AppCoreBase::Run(int argc, char** argv) {
1274 void AppCoreBase::Init(int argc, char** argv) {
1276 impl_->suspended_state_ = false;
1277 impl_->allowed_bg_ = false;
1278 impl_->argc_ = argc;
1279 impl_->argv_ = argv;
1280 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1281 sigterm_handler.Restore();
1282 if (impl_->loop_delegator_)
1283 impl_->loop_delegator_->OnLoopInit(argc, argv);
1285 OnLoopInit(argc, argv);
1287 impl_->signal_handler_source_ = g_unix_signal_add(SIGTERM,
1288 [](gpointer data) -> gboolean {
1289 _W("sigterm handler");
1290 if (context_ != nullptr) {
1292 context_->impl_->signal_handler_source_ = 0;
1295 return G_SOURCE_REMOVE;
1298 if (impl_->signal_handler_source_ == 0)
1299 _E("Failed to add sigterm handler.");
1301 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1303 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:PLUGIN_INIT");
1304 impl_->PluginInit(argc, argv);
1305 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1307 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1308 GLib::IdleAdd(Impl::InitSuspendCb, this);
1310 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1311 if (!impl_->dirty_) {
1312 impl_->dirty_ = true;
1314 for (auto& e : impl_->events_) {
1315 if (impl_->core_delegator_)
1316 impl_->core_delegator_->OnSetEvent(e->GetType());
1318 OnSetEvent(e->GetType());
1321 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1323 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1324 impl_->VerifyLanguage();
1325 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1327 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1328 impl_->SetDefaultEvents();
1329 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1331 if (impl_->core_delegator_)
1332 impl_->core_delegator_->OnSetI18n();
1336 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1338 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1340 if (impl_->core_delegator_)
1341 create = impl_->core_delegator_->OnCreate();
1343 create = OnCreate();
1344 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1346 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1350 if (impl_->loop_delegator_)
1351 impl_->loop_delegator_->OnLoopRun();
1356 void AppCoreBase::Fini() {
1357 if (impl_->signal_handler_source_) {
1358 g_source_remove(impl_->signal_handler_source_);
1359 impl_->signal_handler_source_ = 0;
1365 void AppCoreBase::Dispose() {
1366 aul_status_update(STATUS_DYING);
1368 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1370 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1371 if (impl_->core_delegator_)
1372 impl_->core_delegator_->OnTerminate();
1375 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1377 for (auto& e : impl_->events_) {
1378 if (impl_->core_delegator_)
1379 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1381 OnUnsetEvent(e->GetType());
1384 impl_->UnsetDefaultEvents();
1386 GLib::SourceRemove(impl_->sid_);
1390 RemoveSuspendTimer();
1391 impl_->PluginFini();
1392 impl_->dirty_ = false;
1393 if (impl_->loop_delegator_)
1394 impl_->loop_delegator_->OnLoopFinish();
1399 void AppCoreBase::SetFeature(int feature) {
1400 impl_->feature_ = feature;
1403 int AppCoreBase::GetFeature() const {
1404 return impl_->feature_;
1407 void AppCoreBase::Impl::PluginInit(int argc, char** argv) {
1408 plugin_.reset(AppCorePlugin::Load());
1412 plugin_->Init(argc, argv);
1415 void AppCoreBase::Impl::PluginFini() {
1422 } // namespace tizen_cpp