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.
19 #include <aul_app_lifecycle.h>
20 #include <aul_watchdog.h>
21 #include <bundle_internal.h>
27 #include <linux/limits.h>
30 #include <sensor_internal.h>
35 #include <sys/types.h>
36 #include <system_info.h>
51 #include "app-core-cpp/app_core_base.hh"
52 #include "common/glib_private.hh"
53 #include "common/log_private.hh"
55 extern "C" void aul_finalize();
58 AppCoreBase* AppCoreBase::context_ = nullptr;
71 TizenProfile TizenProfileGet() {
72 static TizenProfile profile = TizenProfile::Unknown;
73 if (__builtin_expect(profile != TizenProfile::Unknown, 1))
76 char* profile_name = nullptr;
77 system_info_get_platform_string("http://tizen.org/feature/profile",
79 if (profile_name == nullptr)
82 switch (*profile_name) {
85 profile = TizenProfile::Mobile;
89 profile = TizenProfile::Wearable;
93 profile = TizenProfile::Tv;
97 profile = TizenProfile::Ivi;
100 profile = TizenProfile::Common;
108 constexpr const char PATH_LOCALE[] = "locale";
109 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
110 constexpr const char RESOURCED_FREEZER_PATH[] =
111 "/Org/Tizen/ResourceD/Freezer";
112 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
113 "org.tizen.resourced.freezer";
114 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
121 tizen_cpp::AppCoreBase::RotationState rm;
127 GDBusConnection* __bus;
128 guint __suspend_dbus_handler_initialized;
129 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
133 class AppCoreBase::EventBase::Impl {
135 friend class AppCoreBase;
136 Type type_ = IEvent::Type::START;
137 std::string str_val_;
141 class AppCoreBase::Impl {
143 explicit Impl(AppCoreBase* parent) : parent_(parent) {
144 if (TizenProfileGet() & TizenProfile::Wearable)
145 feature_ |= FEATURE_CHARGER_STATUS;
146 if (!(TizenProfileGet() & TizenProfile::Tv))
147 feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
151 void UnregisterRotationChangedEvent();
152 void RegisterRotationChangedEvent();
153 std::string GetAppName(const char* appid);
154 std::string GetLocaleResourceDir();
157 std::list<std::string> SplitLanguage(const std::string& lang);
158 std::string GetLanguage(std::string lang);
159 void AppendDefaultLangs(std::vector<std::string>& lang_set);
160 std::string GetStringBefore(const char* str, const char* delim);
161 std::map<std::string, std::set<std::string>> GetLangTable();
162 void AppendLangs(const std::string& lang, std::vector<std::string>& lang_set,
163 std::map<std::string, std::set<std::string>>& table);
165 void OnFreezerSignal();
168 void InvokeCallback(T event, IEvent::Type type) {
169 for (auto& i : events_) {
170 if (i->GetType() != type)
173 if (i->GetVal(event) != event ||
174 type == IEvent::Type::START ||
175 type == IEvent::Type::UPDATE_REQUESTED) {
182 static void InitSuspendDbusHandler(gpointer data);
183 static gboolean InitSuspendCb(gpointer data);
184 static gboolean InvokeLangChangeCb(gpointer data);
185 static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
186 const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
187 static void OnLowBatteryCb(keynode_t* key, void* data);
188 static void LockCb(keynode_t* node, void* user_data);
189 static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
190 sensor_data_t* data, void* user_data);
191 static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
192 static void LanguageChangeCb(keynode_t* key, void* data);
193 static void RegionChangeCb(keynode_t* key, void* data);
194 static void LowMemoryCb(keynode_t* key, void* data);
197 RotationState GetRm(sensor_data_t data);
198 void VerifyLanguage();
199 void SetDefaultEvents();
200 void UnsetDefaultEvents();
203 friend class AppCoreBase;
204 AppCoreBase* parent_ = nullptr;
207 char** argv_ = nullptr;
208 bool suspended_state_ = false;
209 bool allowed_bg_ = false;
211 unsigned int tid_ = 0;
212 std::list<std::shared_ptr<EventBase>> events_;
213 std::string locale_dir_;
216 IAppCore* core_delegator_ = nullptr;
217 IMainLoop* loop_delegator_ = nullptr;
220 AppCoreBase::EventBase::EventBase(Type type)
221 : impl_(std::make_unique<EventBase::Impl>()) {
225 AppCoreBase::EventBase::~EventBase() = default;
227 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
231 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
232 return impl_->str_val_;
235 int AppCoreBase::EventBase::GetVal(int cur) const {
239 void AppCoreBase::EventBase::SetVal(std::string val) {
240 impl_->str_val_ = std::move(val);
243 void AppCoreBase::EventBase::SetVal(int val) {
244 impl_->val_ = std::move(val);
247 AppCoreBase::AppCoreBase()
248 : impl_(std::make_unique<AppCoreBase::Impl>(this)) {
249 if (context_ != nullptr) {
250 _E("Context is already initialized");
256 AppCoreBase::~AppCoreBase() {
261 AppCoreBase* AppCoreBase::GetContext() {
262 if (context_ == nullptr) {
263 _E("Context is not initialized.");
270 void AppCoreBase::Impl::ChangeLang() {
271 const char* lang = getenv("LANG");
275 InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
278 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
279 impl_->InvokeCallback(event, type);
282 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
283 impl_->InvokeCallback(event, type);
286 void AppCoreBase::Impl::OnFreezerSignal() {
287 if (!allowed_bg_ && suspended_state_) {
288 parent_->RemoveSuspendTimer();
289 InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
290 IEvent::Type::SUSPENDED_STATE_CHANGE);
291 suspended_state_ = false;
292 parent_->AddSuspendTimer();
296 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
297 if (data.value_count <= 0) {
298 _E("Failed to get sensor data");
299 return ROTATION_UNKNOWN;
302 int event = data.values[0];
304 case AUTO_ROTATION_DEGREE_0:
305 return ROTATION_PORTRAIT_NORMAL;
306 case AUTO_ROTATION_DEGREE_90:
307 return ROTATION_LANDSCAPE_NORMAL;
308 case AUTO_ROTATION_DEGREE_180:
309 return ROTATION_PORTRAIT_REVERSE;
310 case AUTO_ROTATION_DEGREE_270:
311 return ROTATION_LANDSCAPE_REVERSE;
313 return ROTATION_UNKNOWN;
317 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
318 if (__suspend_dbus_handler_initialized)
321 if (__bus == nullptr) {
322 GError* err = nullptr;
323 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
324 if (__bus == nullptr) {
325 _E("Failed to connect to the D-BUS daemon: %s", err->message);
331 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
332 __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
333 RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
334 ReceiveSuspendSignalCb, data, nullptr);
336 if (__suspend_dbus_handler_initialized == 0) {
337 _E("g_dbus_connection_signal_subscribe() is failed.");
341 _D("[__SUSPEND__] suspend signal initialized");
344 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
345 InitSuspendDbusHandler(data);
346 return G_SOURCE_REMOVE;
349 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
350 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
351 base->impl_->sid_ = 0;
352 base->impl_->ChangeLang();
353 return G_SOURCE_REMOVE;
356 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
357 const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
358 gpointer user_data) {
359 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
362 g_variant_get(parameters, "(ii)", &status, &pid);
363 if (pid == getpid() && status == 0) {
364 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
365 base->impl_->OnFreezerSignal();
370 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
371 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
372 if (base->impl_->sid_) {
373 GLib::SourceRemove(base->impl_->sid_);
374 base->impl_->sid_ = 0;
377 char* val = vconf_keynode_get_str(key);
381 base->impl_->UpdateLang();
382 base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
385 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
386 const char* name = vconf_keynode_get_name(key);
390 if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
391 strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
394 char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
397 std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
399 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
400 base->impl_->UpdateRegion();
401 base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
404 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
405 int val = vconf_keynode_get_int(key);
406 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
407 base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
408 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
412 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
414 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
415 if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
416 __rotation.charger_status = vconf_keynode_get_int(keynode);
417 if (__rotation.ref) {
418 if (__rotation.charger_status) {
419 base->impl_->InitRotation();
421 base->impl_->FiniRotation();
425 _D("charger status(%d)", __rotation.charger_status);
429 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
430 AppCoreBase::RotationState rm;
431 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
433 __rotation.lock = !vconf_keynode_get_bool(node);
434 if (__rotation.lock) {
435 _D("Rotation locked");
436 rm = ROTATION_PORTRAIT_NORMAL;
438 _D("Rotation unlocked");
440 bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
442 _E("Failed to get sensor data");
446 rm = base->impl_->GetRm(data);
447 if (rm == ROTATION_UNKNOWN) {
453 if (__rotation.rm == rm)
456 _D("Rotation: %d -> %d", __rotation.rm, rm);
458 base->impl_->InvokeCallback(__rotation.rm,
459 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
462 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
463 unsigned int event_type, sensor_data_t* data, void* user_data) {
470 if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
473 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
474 AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
475 if (rm == ROTATION_UNKNOWN) {
480 _D("Rotation: %d -> %d", __rotation.rm, rm);
482 base->impl_->InvokeCallback(__rotation.rm,
483 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
486 void AppCoreBase::Impl::InitRotation() {
487 if (__rotation.initialized)
490 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
491 __rotation.conn = sensord_connect(sensor);
492 if (__rotation.conn < 0) {
493 _E("Failed to connect sensord");
497 bool r = sensord_register_event(__rotation.conn,
498 AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
499 AutoRotationChangedCb, parent_);
501 _E("Failed to register auto rotation change event");
502 sensord_disconnect(__rotation.conn);
506 r = sensord_start(__rotation.conn, 0);
508 _E("Failed to start sensord");
509 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
510 sensord_disconnect(__rotation.conn);
515 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
516 vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
519 __rotation.lock = !lock;
520 __rotation.initialized = true;
523 void AppCoreBase::Impl::FiniRotation() {
524 if (!__rotation.initialized)
527 vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
528 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
529 sensord_stop(__rotation.conn);
530 sensord_disconnect(__rotation.conn);
533 __rotation.initialized = false;
536 void AppCoreBase::Impl::VerifyLanguage() {
537 const char* env_lang = getenv("LANG");
538 if (env_lang == nullptr)
541 char* lang = vconf_get_str(VCONFKEY_LANGSET);
545 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
547 if (strcmp(env_lang, lang) != 0) {
548 _I("LANG(%s), LANGSET(%s)", env_lang, lang);
549 sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
553 void AppCoreBase::Impl::SetDefaultEvents() {
554 vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
555 int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
558 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
562 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
565 void AppCoreBase::Impl::UnsetDefaultEvents() {
566 vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
567 int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
569 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
571 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
574 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
577 _D("[APP %d] AUL event: AUL_START", getpid());
578 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
579 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
580 if (bg == "ALLOWED_BG") {
581 _D("[__SUSPEND__] allowed background");
582 impl_->allowed_bg_ = true;
583 RemoveSuspendTimer();
587 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
588 if (impl_->core_delegator_)
589 impl_->core_delegator_->OnControl(std::move(b));
591 OnControl(std::move(b));
592 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
595 _D("[APP %d] AUL event: AUL_RESUME", getpid());
596 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
597 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
598 if (bg == "ALLOWED_BG") {
599 _D("[__SUSPEND__] allowed background");
600 impl_->allowed_bg_ = true;
601 RemoveSuspendTimer();
606 _D("[APP %d] AUL event: AUL_TERMINATE", getpid());
607 aul_status_update(STATUS_DYING);
608 if (!impl_->allowed_bg_)
609 RemoveSuspendTimer();
613 case AUL_TERMINATE_INST:
614 case AUL_TERMINATE_BG_INST:
615 case AUL_TERMINATE_BGAPP:
616 _D("[APP %d] AUL event: %d", getpid(), type);
617 if (!impl_->allowed_bg_)
618 RemoveSuspendTimer();
621 _D("[APP %d] AUL event: AUL_WAKE", getpid());
622 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
623 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
624 RemoveSuspendTimer();
625 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
626 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
627 impl_->suspended_state_ = false;
632 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
633 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
634 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
635 RemoveSuspendTimer();
640 case AUL_UPDATE_REQUESTED:
641 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
642 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
645 _D("[APP %d] AUL event: %d", getpid(), type);
653 int AppCoreBase::OnCreate() {
654 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
655 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
656 if (base->impl_->core_delegator_) {
657 return base->impl_->core_delegator_->OnReceive(type,
658 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
660 return base->OnReceive(type,
661 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
663 if (ret < 0 && ret != AUL_R_ECANCELED) {
664 _E("aul_launch_init() is failed. error(%d)", ret);
668 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
670 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
677 int AppCoreBase::OnControl(tizen_base::Bundle b) {
681 int AppCoreBase::OnTerminate() {
686 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
687 impl_->core_delegator_ = delegator;
690 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
691 impl_->loop_delegator_ = delegator;
694 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
695 if (appid == nullptr)
698 /* com.vendor.name -> name */
699 const char* name_token = strrchr(appid, '.');
700 if (name_token == nullptr)
707 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
708 const char* res_path = aul_get_app_resource_path();
709 if (res_path == nullptr) {
710 _E("Failed to get resource path");
714 return std::string(res_path) + PATH_LOCALE;
717 int AppCoreBase::OnSetI18n() {
718 char appid[PATH_MAX];
719 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
721 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
725 std::string name = impl_->GetAppName(appid);
729 std::string locale_dir = impl_->GetLocaleResourceDir();
730 if (locale_dir.empty())
733 return SetI18n(move(name), move(locale_dir));
736 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
737 int val = vconf_keynode_get_int(key);
738 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
739 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
740 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
744 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
749 if (__rotation.ref == 0) {
751 if (feature_ & FEATURE_CHARGER_STATUS) {
752 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
753 ChargerStatusChangedCb);
758 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
759 if (__rotation.ref == 0) {
760 if (feature_ & FEATURE_CHARGER_STATUS) {
761 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
762 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
763 ChargerStatusChangedCb, parent_);
764 if (__rotation.charger_status)
774 int AppCoreBase::OnSetEvent(IEvent::Type event) {
776 case IEvent::Type::LOW_BATTERY:
777 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
778 impl_->OnLowBatteryCb, this);
780 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
781 impl_->RegisterRotationChangedEvent();
783 case IEvent::Type::SUSPENDED_STATE_CHANGE:
792 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
794 case IEvent::Type::LOW_BATTERY:
795 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
796 impl_->OnLowBatteryCb);
798 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
799 impl_->UnregisterRotationChangedEvent();
801 case IEvent::Type::SUSPENDED_STATE_CHANGE:
810 int AppCoreBase::OnTrimMemory() {
811 int (*sqlite3_free_heap_memory)(int);
813 sqlite3_free_heap_memory = reinterpret_cast<
814 decltype(sqlite3_free_heap_memory)>(
815 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
816 if (sqlite3_free_heap_memory)
817 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
823 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
825 for (auto& ev : impl_->events_) {
826 if (ev->GetType() == event->GetType()) {
833 if (impl_->core_delegator_)
834 impl_->core_delegator_->OnSetEvent(event->GetType());
836 OnSetEvent(event->GetType());
839 impl_->events_.push_back(move(event));
842 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
844 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
845 if (event.get() == ptr.get()) {
855 void AppCoreBase::FlushMemory() {
856 if (impl_->core_delegator_)
857 impl_->core_delegator_->OnTrimMemory();
862 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
863 _D("[__SUSPEND__] flush case");
864 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
865 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
866 impl_->suspended_state_ = true;
870 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
872 throw std::runtime_error("invalid rotation state");
874 return __rotation.rm;
877 bool AppCoreBase::IsBgAllowed() {
878 return impl_->allowed_bg_;
881 bool AppCoreBase::IsSuspended() {
882 return impl_->suspended_state_;
885 void AppCoreBase::ToggleSuspendedState() {
886 impl_->suspended_state_ = !impl_->suspended_state_;
889 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
890 const std::string& lang) {
891 std::istringstream ss(lang);
892 std::list<std::string> li;
895 while (std::getline(ss, token, ':'))
901 void AppCoreBase::Impl::AppendDefaultLangs(std::vector<std::string>& langs) {
902 langs.push_back("en_US");
903 langs.push_back("en_GB");
904 langs.push_back("en");
907 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
909 if (cstr == nullptr || delim == nullptr)
912 auto str = std::string(cstr);
913 auto idx = str.find(delim);
914 return str.substr(0, idx);
917 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
918 if (locale_dir_.empty())
921 DIR* dp = opendir(locale_dir_.c_str());
925 std::map<std::string, std::set<std::string>> table;
926 struct dirent *dentry;
927 while ((dentry = readdir(dp)) != nullptr) {
928 if (!strcmp(dentry->d_name, ".") ||
929 !strcmp(dentry->d_name, ".."))
932 std::string buf = locale_dir_ + "/" + dentry->d_name;
933 struct stat stat_buf;
934 int ret = stat(buf.c_str(), &stat_buf);
935 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
938 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
939 if (parent_lang.empty()) {
944 table[parent_lang].insert(dentry->d_name);
951 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
952 std::vector<std::string>& langs,
953 std::map<std::string, std::set<std::string>>& table) {
957 langs.push_back(lang);
958 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
959 if (extract_lang.empty())
962 if (std::find(langs.begin(), langs.end(), extract_lang) != langs.end())
965 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
966 if (parent_lang.empty())
969 if (table.find(parent_lang) == table.end())
972 auto it = table[parent_lang].find(extract_lang);
973 if (it != table[parent_lang].end()) {
974 std::string value = *it;
975 if (std::find(langs.begin(), langs.end(), value) == langs.end())
976 langs.push_back(std::move(value));
978 table[parent_lang].erase(it);
982 it = table[parent_lang].find(parent_lang);
983 if (it != table[parent_lang].end()) {
984 std::string value = *it;
985 if (std::find(langs.begin(), langs.end(), value) == langs.end())
986 langs.push_back(std::move(value));
988 table[parent_lang].erase(parent_lang);
992 if (!table[parent_lang].empty()) {
993 auto i = table[parent_lang].begin();
994 std::string value = *i;
995 if (std::find(langs.begin(), langs.end(), value) == langs.end())
996 langs.push_back(std::move(value));
998 table[parent_lang].erase(i);
1002 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
1003 std::list<std::string> l = SplitLanguage(lang);
1007 auto table = GetLangTable();
1011 std::vector<std::string> langs;
1013 AppendLangs(i, langs, table);
1015 AppendDefaultLangs(langs);
1017 for (auto& i : langs) {
1027 void AppCoreBase::Impl::UpdateLang() {
1028 char* lang = vconf_get_str(VCONFKEY_LANGSET);
1029 if (lang == nullptr)
1032 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1033 std::string language = GetLanguage(lang);
1034 if (!language.empty()) {
1035 _D("*****language(%s)", language.c_str());
1036 setenv("LANGUAGE", language.c_str(), 1);
1038 setenv("LANGUAGE", lang, 1);
1040 setenv("LANG", lang, 1);
1041 setenv("LC_MESSAGES", lang, 1);
1042 setenv("LC_ALL", lang, 1);
1043 char* r = setlocale(LC_ALL, "");
1045 r = setlocale(LC_ALL, "en_US.UTF-8");
1047 _D("*****appcore setlocale=%s\n", r);
1049 _D("*****appcore setlocale=\"C\"");
1050 setenv("LC_ALL", "C", 1);
1051 r = setlocale(LC_ALL, "");
1053 _E("failed to setlocale");
1058 void AppCoreBase::Impl::UpdateRegion() {
1059 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1060 if (region == nullptr)
1063 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1064 setenv("LC_CTYPE", region, 1);
1065 setenv("LC_NUMERIC", region, 1);
1066 setenv("LC_TIME", region, 1);
1067 setenv("LC_COLLATE", region, 1);
1068 setenv("LC_MONETARY", region, 1);
1069 setenv("LC_PAPER", region, 1);
1070 setenv("LC_NAME", region, 1);
1071 setenv("LC_ADDRESS", region, 1);
1072 setenv("LC_TELEPHONE", region, 1);
1073 setenv("LC_MEASUREMENT", region, 1);
1074 setenv("LC_IDENTIFICATION", region, 1);
1075 char* r = setlocale(LC_ALL, "");
1077 _D("*****appcore setlocale=%s\n", r);
1079 _D("*****appcore setlocale=\"C\"");
1080 setenv("LC_ALL", "C", 1);
1081 r = setlocale(LC_ALL, "");
1083 _E("failed to setlocale");
1087 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1088 if (domain_name.empty()) {
1093 if (!dir_name.empty())
1094 impl_->locale_dir_ = dir_name;
1096 impl_->UpdateLang();
1097 impl_->UpdateRegion();
1099 char* r = setlocale(LC_ALL, "");
1100 /* if locale is not set properly, try to set "en_US" again */
1102 r = setlocale(LC_ALL, "en_US.UTF-8");
1104 _E("appcore: setlocale() error");
1105 _D("*****appcore setlocale=\"C\"");
1106 setenv("LC_ALL", "C", 1);
1107 r = setlocale(LC_ALL, "");
1109 _E("failed to setlocale");
1114 _D("*****appcore setlocale=%s\n", r);
1116 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1118 _E("appcore: bindtextdomain() error");
1120 r = textdomain(domain_name.c_str());
1122 _E("appcore: textdomain() error");
1127 void AppCoreBase::Exit() {
1128 aul_status_update(STATUS_DYING);
1129 if (impl_->loop_delegator_)
1130 impl_->loop_delegator_->OnLoopExit();
1135 void AppCoreBase::AddSuspendTimer() {
1136 impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1137 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1138 base->FlushMemory();
1143 void AppCoreBase::RemoveSuspendTimer() {
1144 if (impl_->tid_ > 0) {
1145 GLib::SourceRemove(impl_->tid_);
1150 void AppCoreBase::SetDisplayState(DisplayState state) {
1151 __display_state = state;
1154 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1155 return __display_state;
1158 int AppCoreBase::EnableWatchdog() {
1159 _I("[__APPCORE_WATCHDOG__] enable");
1160 return aul_watchdog_enable();
1163 int AppCoreBase::DisableWatchdog() {
1164 _I("[__APPCORE_WATCHDOG__] disable");
1165 return aul_watchdog_disable();
1168 int AppCoreBase::KickWatchdog() {
1169 _I("[__APPCORE_WATCHDOG__] kick");
1170 return aul_watchdog_kick();
1173 void AppCoreBase::Run(int argc, char** argv) {
1178 void AppCoreBase::Init(int argc, char** argv) {
1180 impl_->suspended_state_ = false;
1181 impl_->allowed_bg_ = false;
1182 impl_->argc_ = argc;
1183 impl_->argv_ = argv;
1184 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1185 if (impl_->loop_delegator_)
1186 impl_->loop_delegator_->OnLoopInit(argc, argv);
1188 OnLoopInit(argc, argv);
1190 signal(SIGTERM, [](int n) {
1191 _W("sigterm handler");
1192 if (context_ != nullptr)
1196 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1198 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1199 GLib::IdleAdd(Impl::InitSuspendCb, this);
1201 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1202 if (!impl_->dirty_) {
1203 impl_->dirty_ = true;
1205 for (auto& e : impl_->events_) {
1206 if (impl_->core_delegator_)
1207 impl_->core_delegator_->OnSetEvent(e->GetType());
1209 OnSetEvent(e->GetType());
1212 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1214 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1215 impl_->VerifyLanguage();
1216 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1218 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1219 impl_->SetDefaultEvents();
1220 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1222 if (impl_->core_delegator_)
1223 impl_->core_delegator_->OnSetI18n();
1227 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1229 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1231 if (impl_->core_delegator_)
1232 create = impl_->core_delegator_->OnCreate();
1234 create = OnCreate();
1235 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1237 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1241 if (impl_->loop_delegator_)
1242 impl_->loop_delegator_->OnLoopRun();
1247 void AppCoreBase::Fini() {
1251 void AppCoreBase::Dispose() {
1252 aul_status_update(STATUS_DYING);
1254 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1256 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1257 if (impl_->core_delegator_)
1258 impl_->core_delegator_->OnTerminate();
1261 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1263 for (auto& e : impl_->events_) {
1264 if (impl_->core_delegator_)
1265 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1267 OnUnsetEvent(e->GetType());
1270 impl_->UnsetDefaultEvents();
1272 GLib::SourceRemove(impl_->sid_);
1276 RemoveSuspendTimer();
1277 impl_->dirty_ = false;
1278 if (impl_->loop_delegator_)
1279 impl_->loop_delegator_->OnLoopFinish();
1284 void AppCoreBase::SetFeature(int feature) {
1285 impl_->feature_ = feature;
1288 int AppCoreBase::GetFeature() const {
1289 return impl_->feature_;
1292 } // namespace tizen_cpp