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.
18 #include <aul_app_lifecycle.h>
19 #include <aul_watchdog.h>
20 #include <bundle_internal.h>
26 #include <linux/limits.h>
29 #include <sensor_internal.h>
33 #include <sys/types.h>
34 #include <system_info.h>
47 #include "app-core-cpp/app_core_base.hh"
48 #include "common/glib_private.hh"
49 #include "common/log_private.hh"
51 extern "C" void aul_finalize();
54 AppCoreBase* AppCoreBase::context_ = nullptr;
67 TizenProfile TizenProfileGet() {
68 static TizenProfile profile = TizenProfile::Unknown;
69 if (__builtin_expect(profile != TizenProfile::Unknown, 1))
72 char* profile_name = nullptr;
73 system_info_get_platform_string("http://tizen.org/feature/profile",
75 if (profile_name == nullptr)
78 switch (*profile_name) {
81 profile = TizenProfile::Mobile;
85 profile = TizenProfile::Wearable;
89 profile = TizenProfile::Tv;
93 profile = TizenProfile::Ivi;
96 profile = TizenProfile::Common;
104 constexpr const char PATH_LOCALE[] = "locale";
105 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
106 constexpr const char RESOURCED_FREEZER_PATH[] =
107 "/Org/Tizen/ResourceD/Freezer";
108 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
109 "org.tizen.resourced.freezer";
110 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
117 tizen_cpp::AppCoreBase::RotationState rm;
123 GDBusConnection* __bus;
124 guint __suspend_dbus_handler_initialized;
125 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
129 class AppCoreBase::EventBase::Impl {
131 friend class AppCoreBase;
132 Type type_ = IEvent::Type::START;
133 std::string str_val_;
137 class AppCoreBase::Impl {
139 explicit Impl(AppCoreBase* parent) : parent_(parent) {
140 if (TizenProfileGet() & TizenProfile::Wearable)
141 feature_ |= FEATURE_CHARGER_STATUS;
142 if (!(TizenProfileGet() & TizenProfile::Tv))
143 feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
147 void UnregisterRotationChangedEvent();
148 void RegisterRotationChangedEvent();
149 std::string GetAppName(const char* appid);
150 std::string GetLocaleResourceDir();
153 std::list<std::string> SplitLanguage(const std::string& lang);
154 std::string GetLanguage(std::string lang);
155 void AppendDefaultLangs(std::set<std::string>& lang_set);
156 std::string GetStringBefore(const char* str, const char* delim);
157 std::map<std::string, std::set<std::string>> GetLangTable();
158 void AppendLangs(const std::string& lang, std::set<std::string>& lang_set,
159 std::map<std::string, std::set<std::string>>& table);
161 void OnFreezerSignal();
164 void InvokeCallback(T event, IEvent::Type type) {
165 for (auto& i : events_) {
166 if (i->GetType() != type)
169 if (i->GetVal(event) != event ||
170 type == IEvent::Type::START ||
171 type == IEvent::Type::UPDATE_REQUESTED) {
178 static void InitSuspendDbusHandler(gpointer data);
179 static gboolean InitSuspendCb(gpointer data);
180 static gboolean InvokeLangChangeCb(gpointer data);
181 static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
182 const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
183 static void OnLowBatteryCb(keynode_t* key, void* data);
184 static void LockCb(keynode_t* node, void* user_data);
185 static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
186 sensor_data_t* data, void* user_data);
187 static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
188 static void LanguageChangeCb(keynode_t* key, void* data);
189 static void RegionChangeCb(keynode_t* key, void* data);
190 static void LowMemoryCb(keynode_t* key, void* data);
193 RotationState GetRm(sensor_data_t data);
194 void VerifyLanguage();
195 void SetDefaultEvents();
196 void UnsetDefaultEvents();
199 friend class AppCoreBase;
200 AppCoreBase* parent_ = nullptr;
203 char** argv_ = nullptr;
204 bool suspended_state_ = false;
205 bool allowed_bg_ = false;
207 unsigned int tid_ = 0;
208 std::list<std::shared_ptr<EventBase>> events_;
209 std::string locale_dir_;
212 IAppCore* core_delegator_ = nullptr;
213 IMainLoop* loop_delegator_ = nullptr;
216 AppCoreBase::EventBase::EventBase(Type type)
217 : impl_(std::make_unique<EventBase::Impl>()) {
221 AppCoreBase::EventBase::~EventBase() = default;
223 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
227 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
228 return impl_->str_val_;
231 int AppCoreBase::EventBase::GetVal(int cur) const {
235 void AppCoreBase::EventBase::SetVal(std::string val) {
236 impl_->str_val_ = std::move(val);
239 void AppCoreBase::EventBase::SetVal(int val) {
240 impl_->val_ = std::move(val);
243 AppCoreBase::AppCoreBase()
244 : impl_(std::make_unique<AppCoreBase::Impl>(this)) {
245 if (context_ != nullptr) {
246 _E("Context is already initialized");
252 AppCoreBase::~AppCoreBase() = default;
254 AppCoreBase* AppCoreBase::GetContext() {
255 if (context_ == nullptr) {
256 _E("Context is not initialized.");
263 void AppCoreBase::Impl::ChangeLang() {
264 const char* lang = getenv("LANG");
268 InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
271 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
272 impl_->InvokeCallback(event, type);
275 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
276 impl_->InvokeCallback(event, type);
279 void AppCoreBase::Impl::OnFreezerSignal() {
280 if (!allowed_bg_ && suspended_state_) {
281 parent_->RemoveSuspendTimer();
282 InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
283 IEvent::Type::SUSPENDED_STATE_CHANGE);
284 suspended_state_ = false;
285 parent_->AddSuspendTimer();
289 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
290 if (data.value_count <= 0) {
291 _E("Failed to get sensor data");
292 return ROTATION_UNKNOWN;
295 int event = data.values[0];
297 case AUTO_ROTATION_DEGREE_0:
298 return ROTATION_PORTRAIT_NORMAL;
299 case AUTO_ROTATION_DEGREE_90:
300 return ROTATION_LANDSCAPE_NORMAL;
301 case AUTO_ROTATION_DEGREE_180:
302 return ROTATION_PORTRAIT_REVERSE;
303 case AUTO_ROTATION_DEGREE_270:
304 return ROTATION_LANDSCAPE_REVERSE;
306 return ROTATION_UNKNOWN;
310 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
311 if (__suspend_dbus_handler_initialized)
314 if (__bus == nullptr) {
315 GError* err = nullptr;
316 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
317 if (__bus == nullptr) {
318 _E("Failed to connect to the D-BUS daemon: %s", err->message);
324 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
325 __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
326 RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
327 ReceiveSuspendSignalCb, data, nullptr);
329 if (__suspend_dbus_handler_initialized == 0) {
330 _E("g_dbus_connection_signal_subscribe() is failed.");
334 _D("[__SUSPEND__] suspend signal initialized");
337 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
338 InitSuspendDbusHandler(data);
339 return G_SOURCE_REMOVE;
342 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
343 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
344 base->impl_->sid_ = 0;
345 base->impl_->ChangeLang();
346 return G_SOURCE_REMOVE;
349 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
350 const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
351 gpointer user_data) {
352 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
355 g_variant_get(parameters, "(ii)", &status, &pid);
356 if (pid == getpid() && status == 0) {
357 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
358 base->impl_->OnFreezerSignal();
363 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
364 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
365 if (base->impl_->sid_) {
366 GLib::SourceRemove(base->impl_->sid_);
367 base->impl_->sid_ = 0;
370 char* val = vconf_keynode_get_str(key);
374 base->impl_->UpdateLang();
375 base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
378 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
379 const char* name = vconf_keynode_get_name(key);
383 if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
384 strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
387 char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
390 std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
392 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
393 base->impl_->UpdateRegion();
394 base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
397 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
398 int val = vconf_keynode_get_int(key);
399 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
400 base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
401 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
405 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
407 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
408 if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
409 __rotation.charger_status = vconf_keynode_get_int(keynode);
410 if (__rotation.ref) {
411 if (__rotation.charger_status) {
412 base->impl_->InitRotation();
414 base->impl_->FiniRotation();
418 _D("charger status(%d)", __rotation.charger_status);
422 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
423 AppCoreBase::RotationState rm;
424 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
426 __rotation.lock = !vconf_keynode_get_bool(node);
427 if (__rotation.lock) {
428 _D("Rotation locked");
429 rm = ROTATION_PORTRAIT_NORMAL;
431 _D("Rotation unlocked");
433 bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
435 _E("Failed to get sensor data");
439 rm = base->impl_->GetRm(data);
440 if (rm == ROTATION_UNKNOWN) {
446 if (__rotation.rm == rm)
449 _D("Rotation: %d -> %d", __rotation.rm, rm);
451 base->impl_->InvokeCallback(__rotation.rm,
452 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
455 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
456 unsigned int event_type, sensor_data_t* data, void* user_data) {
463 if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
466 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
467 AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
468 if (rm == ROTATION_UNKNOWN) {
473 _D("Rotation: %d -> %d", __rotation.rm, rm);
475 base->impl_->InvokeCallback(__rotation.rm,
476 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
479 void AppCoreBase::Impl::InitRotation() {
480 if (__rotation.initialized)
483 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
484 __rotation.conn = sensord_connect(sensor);
485 if (__rotation.conn < 0) {
486 _E("Failed to connect sensord");
490 bool r = sensord_register_event(__rotation.conn,
491 AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
492 AutoRotationChangedCb, parent_);
494 _E("Failed to register auto rotation change event");
495 sensord_disconnect(__rotation.conn);
499 r = sensord_start(__rotation.conn, 0);
501 _E("Failed to start sensord");
502 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
503 sensord_disconnect(__rotation.conn);
508 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
509 vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
512 __rotation.lock = !lock;
513 __rotation.initialized = true;
516 void AppCoreBase::Impl::FiniRotation() {
517 if (!__rotation.initialized)
520 vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
521 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
522 sensord_stop(__rotation.conn);
523 sensord_disconnect(__rotation.conn);
526 __rotation.initialized = false;
529 void AppCoreBase::Impl::VerifyLanguage() {
530 const char* env_lang = getenv("LANG");
531 if (env_lang == nullptr)
534 char* lang = vconf_get_str(VCONFKEY_LANGSET);
538 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
540 if (strcmp(env_lang, lang) != 0) {
541 _I("LANG(%s), LANGSET(%s)", env_lang, lang);
542 sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
546 void AppCoreBase::Impl::SetDefaultEvents() {
547 vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
548 int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
551 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
555 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
558 void AppCoreBase::Impl::UnsetDefaultEvents() {
559 vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
560 int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
562 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
564 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
567 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
570 _D("[APP %d] AUL event: AUL_START", getpid());
571 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
572 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
573 if (bg == "ALLOWED_BG") {
574 _D("[__SUSPEND__] allowed background");
575 impl_->allowed_bg_ = true;
576 RemoveSuspendTimer();
580 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
581 if (impl_->core_delegator_)
582 impl_->core_delegator_->OnControl(std::move(b));
584 OnControl(std::move(b));
585 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
588 _D("[APP %d] AUL event: AUL_RESUME", getpid());
589 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
590 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
591 if (bg == "ALLOWED_BG") {
592 _D("[__SUSPEND__] allowed background");
593 impl_->allowed_bg_ = true;
594 RemoveSuspendTimer();
599 _D("[APP %d] AUL event: AUL_TERMINATE", getpid());
600 aul_status_update(STATUS_DYING);
601 if (!impl_->allowed_bg_)
602 RemoveSuspendTimer();
606 case AUL_TERMINATE_INST:
607 case AUL_TERMINATE_BG_INST:
608 case AUL_TERMINATE_BGAPP:
609 _D("[APP %d] AUL event: %d", getpid(), type);
610 if (!impl_->allowed_bg_)
611 RemoveSuspendTimer();
614 _D("[APP %d] AUL event: AUL_WAKE", getpid());
615 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
616 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
617 RemoveSuspendTimer();
618 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
619 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
620 impl_->suspended_state_ = false;
625 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
626 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
627 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
628 RemoveSuspendTimer();
633 case AUL_UPDATE_REQUESTED:
634 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
635 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
638 _D("[APP %d] AUL event: %d", getpid(), type);
646 int AppCoreBase::OnCreate() {
647 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
648 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
649 if (base->impl_->core_delegator_) {
650 return base->impl_->core_delegator_->OnReceive(type,
651 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
653 return base->OnReceive(type,
654 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
656 if (ret < 0 && ret != AUL_R_ECANCELED) {
657 _E("aul_launch_init() is failed. error(%d)", ret);
661 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
663 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
670 int AppCoreBase::OnControl(tizen_base::Bundle b) {
674 int AppCoreBase::OnTerminate() {
679 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
680 impl_->core_delegator_ = delegator;
683 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
684 impl_->loop_delegator_ = delegator;
687 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
688 if (appid == nullptr)
691 /* com.vendor.name -> name */
692 const char* name_token = strrchr(appid, '.');
693 if (name_token == nullptr)
700 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
701 const char* res_path = aul_get_app_resource_path();
702 if (res_path == nullptr) {
703 _E("Failed to get resource path");
707 return std::string(res_path) + PATH_LOCALE;
710 int AppCoreBase::OnSetI18n() {
711 char appid[PATH_MAX];
712 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
714 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
718 std::string name = impl_->GetAppName(appid);
722 std::string locale_dir = impl_->GetLocaleResourceDir();
723 if (locale_dir.empty())
726 return SetI18n(move(name), move(locale_dir));
729 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
730 int val = vconf_keynode_get_int(key);
731 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
732 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
733 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
737 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
742 if (__rotation.ref == 0) {
744 if (feature_ & FEATURE_CHARGER_STATUS) {
745 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
746 ChargerStatusChangedCb);
751 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
752 if (__rotation.ref == 0) {
753 if (feature_ & FEATURE_CHARGER_STATUS) {
754 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
755 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
756 ChargerStatusChangedCb, parent_);
757 if (__rotation.charger_status)
767 int AppCoreBase::OnSetEvent(IEvent::Type event) {
769 case IEvent::Type::LOW_BATTERY:
770 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
771 impl_->OnLowBatteryCb, this);
773 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
774 impl_->RegisterRotationChangedEvent();
776 case IEvent::Type::SUSPENDED_STATE_CHANGE:
785 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
787 case IEvent::Type::LOW_BATTERY:
788 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
789 impl_->OnLowBatteryCb);
791 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
792 impl_->UnregisterRotationChangedEvent();
794 case IEvent::Type::SUSPENDED_STATE_CHANGE:
803 int AppCoreBase::OnTrimMemory() {
804 int (*sqlite3_free_heap_memory)(int);
806 sqlite3_free_heap_memory = reinterpret_cast<
807 decltype(sqlite3_free_heap_memory)>(
808 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
809 if (sqlite3_free_heap_memory)
810 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
816 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
818 for (auto& ev : impl_->events_) {
819 if (ev->GetType() == event->GetType()) {
826 if (impl_->core_delegator_)
827 impl_->core_delegator_->OnSetEvent(event->GetType());
829 OnSetEvent(event->GetType());
832 impl_->events_.push_back(move(event));
835 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
837 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
838 if (event.get() == ptr.get()) {
848 void AppCoreBase::FlushMemory() {
849 if (impl_->core_delegator_)
850 impl_->core_delegator_->OnTrimMemory();
855 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
856 _D("[__SUSPEND__] flush case");
857 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
858 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
859 impl_->suspended_state_ = true;
863 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
865 throw std::runtime_error("invalid rotation state");
867 return __rotation.rm;
870 bool AppCoreBase::IsBgAllowed() {
871 return impl_->allowed_bg_;
874 bool AppCoreBase::IsSuspended() {
875 return impl_->suspended_state_;
878 void AppCoreBase::ToggleSuspendedState() {
879 impl_->suspended_state_ = !impl_->suspended_state_;
882 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
883 const std::string& lang) {
884 std::istringstream ss(lang);
885 std::list<std::string> li;
888 while (std::getline(ss, token, ':'))
894 void AppCoreBase::Impl::AppendDefaultLangs(std::set<std::string>& lang_set) {
895 lang_set.insert({"en_US", "en_GB", "en"});
898 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
900 if (cstr == nullptr || delim == nullptr)
903 auto str = std::string(cstr);
904 auto idx = str.find(delim);
905 return str.substr(0, idx);
908 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
909 if (locale_dir_.empty())
912 DIR* dp = opendir(locale_dir_.c_str());
916 std::map<std::string, std::set<std::string>> table;
917 struct dirent *dentry;
918 while ((dentry = readdir(dp)) != nullptr) {
919 if (!strcmp(dentry->d_name, ".") ||
920 !strcmp(dentry->d_name, ".."))
923 std::string buf = locale_dir_ + "/" + dentry->d_name;
924 struct stat stat_buf;
925 int ret = stat(buf.c_str(), &stat_buf);
926 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
929 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
930 if (parent_lang.empty()) {
935 table[parent_lang].insert(dentry->d_name);
942 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
943 std::set<std::string>& lang_set,
944 std::map<std::string, std::set<std::string>>& table) {
948 lang_set.insert(lang);
949 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
950 if (extract_lang.empty())
953 if (lang_set.find(extract_lang) != lang_set.end())
956 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
957 if (parent_lang.empty())
960 if (table.find(parent_lang) == table.end())
963 auto it = table[parent_lang].find(extract_lang);
964 if (it != table[parent_lang].end()) {
965 lang_set.insert(move(*it));
966 table[parent_lang].erase(it);
970 it = table[parent_lang].find(parent_lang);
971 if (it != table[parent_lang].end()) {
972 lang_set.insert(move(*it));
973 table[parent_lang].erase(parent_lang);
977 if (!table[parent_lang].empty()) {
978 auto i = table[parent_lang].begin();
979 lang_set.insert(move(*i));
980 table[parent_lang].erase(i);
984 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
985 std::list<std::string> l = SplitLanguage(lang);
989 auto table = GetLangTable();
993 std::set<std::string> lang_set {};
995 AppendLangs(i, lang_set, table);
997 AppendDefaultLangs(lang_set);
999 for (auto& i : lang_set) {
1003 ret = i + ":" + ret;
1009 void AppCoreBase::Impl::UpdateLang() {
1010 char* lang = vconf_get_str(VCONFKEY_LANGSET);
1011 if (lang == nullptr)
1014 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1015 std::string language = GetLanguage(lang);
1016 if (!language.empty()) {
1017 _D("*****language(%s)", language.c_str());
1018 setenv("LANGUAGE", language.c_str(), 1);
1020 setenv("LANGUAGE", lang, 1);
1022 setenv("LANG", lang, 1);
1023 setenv("LC_MESSAGES", lang, 1);
1024 setenv("LC_ALL", lang, 1);
1025 char* r = setlocale(LC_ALL, "");
1027 r = setlocale(LC_ALL, "en_US.UTF-8");
1029 _D("*****appcore setlocale=%s\n", r);
1031 _D("*****appcore setlocale=\"C\"");
1032 setenv("LC_ALL", "C", 1);
1033 r = setlocale(LC_ALL, "");
1035 _E("failed to setlocale");
1040 void AppCoreBase::Impl::UpdateRegion() {
1041 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1042 if (region == nullptr)
1045 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1046 setenv("LC_CTYPE", region, 1);
1047 setenv("LC_NUMERIC", region, 1);
1048 setenv("LC_TIME", region, 1);
1049 setenv("LC_COLLATE", region, 1);
1050 setenv("LC_MONETARY", region, 1);
1051 setenv("LC_PAPER", region, 1);
1052 setenv("LC_NAME", region, 1);
1053 setenv("LC_ADDRESS", region, 1);
1054 setenv("LC_TELEPHONE", region, 1);
1055 setenv("LC_MEASUREMENT", region, 1);
1056 setenv("LC_IDENTIFICATION", region, 1);
1057 char* r = setlocale(LC_ALL, "");
1059 _D("*****appcore setlocale=%s\n", r);
1061 _D("*****appcore setlocale=\"C\"");
1062 setenv("LC_ALL", "C", 1);
1063 r = setlocale(LC_ALL, "");
1065 _E("failed to setlocale");
1069 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1070 if (domain_name.empty()) {
1075 if (!dir_name.empty())
1076 impl_->locale_dir_ = dir_name;
1078 impl_->UpdateLang();
1079 impl_->UpdateRegion();
1081 char* r = setlocale(LC_ALL, "");
1082 /* if locale is not set properly, try to set "en_US" again */
1084 r = setlocale(LC_ALL, "en_US.UTF-8");
1086 _E("appcore: setlocale() error");
1087 _D("*****appcore setlocale=\"C\"");
1088 setenv("LC_ALL", "C", 1);
1089 r = setlocale(LC_ALL, "");
1091 _E("failed to setlocale");
1096 _D("*****appcore setlocale=%s\n", r);
1098 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1100 _E("appcore: bindtextdomain() error");
1102 r = textdomain(domain_name.c_str());
1104 _E("appcore: textdomain() error");
1109 void AppCoreBase::Exit() {
1110 aul_status_update(STATUS_DYING);
1111 if (impl_->loop_delegator_)
1112 impl_->loop_delegator_->OnLoopExit();
1117 void AppCoreBase::AddSuspendTimer() {
1118 impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1119 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1120 base->FlushMemory();
1125 void AppCoreBase::RemoveSuspendTimer() {
1126 if (impl_->tid_ > 0) {
1127 GLib::SourceRemove(impl_->tid_);
1132 void AppCoreBase::SetDisplayState(DisplayState state) {
1133 __display_state = state;
1136 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1137 return __display_state;
1140 int AppCoreBase::EnableWatchdog() {
1141 _I("[__APPCORE_WATCHDOG__] enable");
1142 return aul_watchdog_enable();
1145 int AppCoreBase::DisableWatchdog() {
1146 _I("[__APPCORE_WATCHDOG__] disable");
1147 return aul_watchdog_disable();
1150 int AppCoreBase::KickWatchdog() {
1151 _I("[__APPCORE_WATCHDOG__] kick");
1152 return aul_watchdog_kick();
1155 void AppCoreBase::Run(int argc, char** argv) {
1160 void AppCoreBase::Init(int argc, char** argv) {
1162 impl_->suspended_state_ = false;
1163 impl_->allowed_bg_ = false;
1164 impl_->argc_ = argc;
1165 impl_->argv_ = argv;
1166 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1167 if (impl_->loop_delegator_)
1168 impl_->loop_delegator_->OnLoopInit(argc, argv);
1170 OnLoopInit(argc, argv);
1171 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1173 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1174 GLib::IdleAdd(Impl::InitSuspendCb, this);
1176 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1177 if (!impl_->dirty_) {
1178 impl_->dirty_ = true;
1180 for (auto& e : impl_->events_) {
1181 if (impl_->core_delegator_)
1182 impl_->core_delegator_->OnSetEvent(e->GetType());
1184 OnSetEvent(e->GetType());
1187 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1189 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1190 impl_->VerifyLanguage();
1191 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1193 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1194 impl_->SetDefaultEvents();
1195 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1197 if (impl_->core_delegator_)
1198 impl_->core_delegator_->OnSetI18n();
1202 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1204 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1206 if (impl_->core_delegator_)
1207 create = impl_->core_delegator_->OnCreate();
1209 create = OnCreate();
1210 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1212 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1216 if (impl_->loop_delegator_)
1217 impl_->loop_delegator_->OnLoopRun();
1222 void AppCoreBase::Fini() {
1226 void AppCoreBase::Dispose() {
1227 aul_status_update(STATUS_DYING);
1229 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1231 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1232 if (impl_->core_delegator_)
1233 impl_->core_delegator_->OnTerminate();
1236 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1238 for (auto& e : impl_->events_) {
1239 if (impl_->core_delegator_)
1240 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1242 OnUnsetEvent(e->GetType());
1245 impl_->UnsetDefaultEvents();
1247 GLib::SourceRemove(impl_->sid_);
1251 RemoveSuspendTimer();
1252 impl_->dirty_ = false;
1253 if (impl_->loop_delegator_)
1254 impl_->loop_delegator_->OnLoopFinish();
1259 void AppCoreBase::SetFeature(int feature) {
1260 impl_->feature_ = feature;
1263 int AppCoreBase::GetFeature() const {
1264 return impl_->feature_;
1267 } // namespace tizen_cpp