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>
45 #include "app-core-cpp/app_core_base.hh"
46 #include "common/glib_private.hh"
47 #include "common/log_private.hh"
49 extern "C" void aul_finalize();
63 TizenProfile TizenProfileGet() {
64 static TizenProfile profile = TizenProfile::Unknown;
65 if (__builtin_expect(profile != TizenProfile::Unknown, 1))
68 char* profile_name = nullptr;
69 system_info_get_platform_string("http://tizen.org/feature/profile",
71 if (profile_name == nullptr)
74 switch (*profile_name) {
77 profile = TizenProfile::Mobile;
81 profile = TizenProfile::Wearable;
85 profile = TizenProfile::Tv;
89 profile = TizenProfile::Ivi;
92 profile = TizenProfile::Common;
100 constexpr const char PATH_LOCALE[] = "locale";
101 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
102 constexpr const char RESOURCED_FREEZER_PATH[] =
103 "/Org/Tizen/ResourceD/Freezer";
104 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
105 "org.tizen.resourced.freezer";
106 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
113 tizen_cpp::AppCoreBase::RotationState rm;
119 GDBusConnection* __bus;
120 guint __suspend_dbus_handler_initialized;
121 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
125 class AppCoreBase::EventBase::Impl {
127 friend class AppCoreBase;
128 Type type_ = IEvent::Type::START;
129 std::string str_val_;
133 class AppCoreBase::Impl {
135 explicit Impl(AppCoreBase* parent) : parent_(parent) {
136 if (TizenProfileGet() & TizenProfile::Wearable)
137 feature_ |= FEATURE_CHARGER_STATUS;
138 if (!(TizenProfileGet() & TizenProfile::Tv))
139 feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
143 void UnregisterRotationChangedEvent();
144 void RegisterRotationChangedEvent();
145 std::string GetAppName(const char* appid);
146 std::string GetLocaleResourceDir();
149 std::list<std::string> SplitLanguage(const std::string& lang);
150 std::string GetLanguage(std::string lang);
151 void AppendDefaultLangs(std::set<std::string>& lang_set);
152 std::string GetStringBefore(const char* str, const char* delim);
153 std::map<std::string, std::set<std::string>> GetLangTable();
154 void AppendLangs(const std::string& lang, std::set<std::string>& lang_set,
155 std::map<std::string, std::set<std::string>>& table);
157 void OnFreezerSignal();
160 void InvokeCallback(T event, IEvent::Type type) {
161 for (auto& i : events_) {
162 if (i->GetType() != type)
165 if (i->GetVal(event) != event ||
166 type == IEvent::Type::START ||
167 type == IEvent::Type::UPDATE_REQUESTED) {
174 static void InitSuspendDbusHandler(gpointer data);
175 static gboolean InitSuspendCb(gpointer data);
176 static gboolean InvokeLangChangeCb(gpointer data);
177 static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
178 const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
179 static void OnLowBatteryCb(keynode_t* key, void* data);
180 static void LockCb(keynode_t* node, void* user_data);
181 static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
182 sensor_data_t* data, void* user_data);
183 static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
184 static void LanguageChangeCb(keynode_t* key, void* data);
185 static void RegionChangeCb(keynode_t* key, void* data);
186 static void LowMemoryCb(keynode_t* key, void* data);
189 RotationState GetRm(sensor_data_t data);
190 void VerifyLanguage();
191 void SetDefaultEvents();
192 void UnsetDefaultEvents();
195 friend class AppCoreBase;
196 AppCoreBase* parent_ = nullptr;
199 char** argv_ = nullptr;
200 bool suspended_state_ = false;
201 bool allowed_bg_ = false;
203 unsigned int tid_ = 0;
204 std::list<std::shared_ptr<EventBase>> events_;
205 std::string locale_dir_;
208 IAppCore* core_delegator_ = nullptr;
209 IMainLoop* loop_delegator_ = nullptr;
212 AppCoreBase::EventBase::EventBase(Type type)
213 : impl_(std::make_unique<EventBase::Impl>()) {
217 AppCoreBase::EventBase::~EventBase() = default;
219 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
223 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
224 return impl_->str_val_;
227 int AppCoreBase::EventBase::GetVal(int cur) const {
231 void AppCoreBase::EventBase::SetVal(std::string val) {
232 impl_->str_val_ = std::move(val);
235 void AppCoreBase::EventBase::SetVal(int val) {
236 impl_->val_ = std::move(val);
239 AppCoreBase::AppCoreBase() : impl_(std::make_unique<AppCoreBase::Impl>(this)) {}
240 AppCoreBase::~AppCoreBase() = default;
242 void AppCoreBase::Impl::ChangeLang() {
243 const char* lang = getenv("LANG");
247 InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
250 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
251 impl_->InvokeCallback(event, type);
254 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
255 impl_->InvokeCallback(event, type);
258 void AppCoreBase::Impl::OnFreezerSignal() {
259 if (!allowed_bg_ && suspended_state_) {
260 parent_->RemoveSuspendTimer();
261 InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
262 IEvent::Type::SUSPENDED_STATE_CHANGE);
263 suspended_state_ = false;
264 parent_->AddSuspendTimer();
268 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
269 if (data.value_count <= 0) {
270 _E("Failed to get sensor data");
271 return ROTATION_UNKNOWN;
274 int event = data.values[0];
276 case AUTO_ROTATION_DEGREE_0:
277 return ROTATION_PORTRAIT_NORMAL;
278 case AUTO_ROTATION_DEGREE_90:
279 return ROTATION_LANDSCAPE_NORMAL;
280 case AUTO_ROTATION_DEGREE_180:
281 return ROTATION_PORTRAIT_REVERSE;
282 case AUTO_ROTATION_DEGREE_270:
283 return ROTATION_LANDSCAPE_REVERSE;
285 return ROTATION_UNKNOWN;
289 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
290 if (__suspend_dbus_handler_initialized)
293 if (__bus == nullptr) {
294 GError* err = nullptr;
295 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
296 if (__bus == nullptr) {
297 _E("Failed to connect to the D-BUS daemon: %s", err->message);
303 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
304 __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
305 RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
306 ReceiveSuspendSignalCb, data, nullptr);
308 if (__suspend_dbus_handler_initialized == 0) {
309 _E("g_dbus_connection_signal_subscribe() is failed.");
313 _D("[__SUSPEND__] suspend signal initialized");
316 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
317 InitSuspendDbusHandler(data);
318 return G_SOURCE_REMOVE;
321 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
322 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
323 base->impl_->sid_ = 0;
324 base->impl_->ChangeLang();
325 return G_SOURCE_REMOVE;
328 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
329 const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
330 gpointer user_data) {
331 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
334 g_variant_get(parameters, "(ii)", &status, &pid);
335 if (pid == getpid() && status == 0) {
336 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
337 base->impl_->OnFreezerSignal();
342 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
343 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
344 if (base->impl_->sid_) {
345 GLib::SourceRemove(base->impl_->sid_);
346 base->impl_->sid_ = 0;
349 char* val = vconf_keynode_get_str(key);
353 base->impl_->UpdateLang();
354 base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
357 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
358 const char* name = vconf_keynode_get_name(key);
362 if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
363 strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
366 char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
369 std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
371 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
372 base->impl_->UpdateRegion();
373 base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
376 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
377 int val = vconf_keynode_get_int(key);
378 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
379 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
380 base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
385 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
387 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
388 if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
389 __rotation.charger_status = vconf_keynode_get_int(keynode);
390 if (__rotation.ref) {
391 if (__rotation.charger_status) {
392 base->impl_->InitRotation();
394 base->impl_->FiniRotation();
398 _D("charger status(%d)", __rotation.charger_status);
402 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
403 AppCoreBase::RotationState rm;
404 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
406 __rotation.lock = !vconf_keynode_get_bool(node);
407 if (__rotation.lock) {
408 _D("Rotation locked");
409 rm = ROTATION_PORTRAIT_NORMAL;
411 _D("Rotation unlocked");
413 bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
415 _E("Failed to get sensor data");
419 rm = base->impl_->GetRm(data);
420 if (rm == ROTATION_UNKNOWN) {
426 if (__rotation.rm == rm)
429 _D("Rotation: %d -> %d", __rotation.rm, rm);
431 base->impl_->InvokeCallback(__rotation.rm,
432 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
435 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
436 unsigned int event_type, sensor_data_t* data, void* user_data) {
443 if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
446 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
447 AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
448 if (rm == ROTATION_UNKNOWN) {
453 _D("Rotation: %d -> %d", __rotation.rm, rm);
455 base->impl_->InvokeCallback(__rotation.rm,
456 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
459 void AppCoreBase::Impl::InitRotation() {
460 if (__rotation.initialized)
463 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
464 __rotation.conn = sensord_connect(sensor);
465 if (__rotation.conn < 0) {
466 _E("Failed to connect sensord");
470 bool r = sensord_register_event(__rotation.conn,
471 AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
472 AutoRotationChangedCb, parent_);
474 _E("Failed to register auto rotation change event");
475 sensord_disconnect(__rotation.conn);
479 r = sensord_start(__rotation.conn, 0);
481 _E("Failed to start sensord");
482 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
483 sensord_disconnect(__rotation.conn);
488 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
489 vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
492 __rotation.lock = !lock;
493 __rotation.initialized = true;
496 void AppCoreBase::Impl::FiniRotation() {
497 if (!__rotation.initialized)
500 vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
501 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
502 sensord_stop(__rotation.conn);
503 sensord_disconnect(__rotation.conn);
506 __rotation.initialized = false;
509 void AppCoreBase::Impl::VerifyLanguage() {
510 const char* env_lang = getenv("LANG");
511 if (env_lang == nullptr)
514 char* lang = vconf_get_str(VCONFKEY_LANGSET);
518 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
520 if (strcmp(env_lang, lang) != 0) {
521 _I("LANG(%s), LANGSET(%s)", env_lang, lang);
522 sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
526 void AppCoreBase::Impl::SetDefaultEvents() {
527 vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
528 int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
531 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
535 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
538 void AppCoreBase::Impl::UnsetDefaultEvents() {
539 vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
540 int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
542 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
544 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
547 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
550 _D("[APP %d] AUL event: AUL_START", getpid());
551 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
552 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
553 if (bg == "ALLOWED_BG") {
554 _D("[__SUSPEND__] allowed background");
555 impl_->allowed_bg_ = true;
556 RemoveSuspendTimer();
560 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
561 if (impl_->core_delegator_)
562 impl_->core_delegator_->OnControl(std::move(b));
564 OnControl(std::move(b));
565 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
568 _D("[APP %d] AUL event: AUL_RESUME", getpid());
569 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
570 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
571 if (bg == "ALLOWED_BG") {
572 _D("[__SUSPEND__] allowed background");
573 impl_->allowed_bg_ = true;
574 RemoveSuspendTimer();
579 _D("[APP %d] AUL event: AUL_TERMINATE", getpid());
580 aul_status_update(STATUS_DYING);
581 if (!impl_->allowed_bg_)
582 RemoveSuspendTimer();
586 case AUL_TERMINATE_INST:
587 case AUL_TERMINATE_BG_INST:
588 case AUL_TERMINATE_BGAPP:
589 _D("[APP %d] AUL event: %d", getpid(), type);
590 if (!impl_->allowed_bg_)
591 RemoveSuspendTimer();
594 _D("[APP %d] AUL event: AUL_WAKE", getpid());
595 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
596 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
597 RemoveSuspendTimer();
598 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
599 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
600 impl_->suspended_state_ = false;
605 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
606 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
607 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
608 RemoveSuspendTimer();
613 case AUL_UPDATE_REQUESTED:
614 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
615 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
618 _D("[APP %d] AUL event: %d", getpid(), type);
626 int AppCoreBase::OnCreate() {
627 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
628 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
629 if (base->impl_->core_delegator_) {
630 return base->impl_->core_delegator_->OnReceive(type,
631 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
633 return base->OnReceive(type,
634 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
636 if (ret < 0 && ret != AUL_R_ECANCELED) {
637 _E("aul_launch_init() is failed. error(%d)", ret);
641 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
643 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
650 int AppCoreBase::OnControl(tizen_base::Bundle b) {
654 int AppCoreBase::OnTerminate() {
659 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
660 impl_->core_delegator_ = delegator;
663 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
664 impl_->loop_delegator_ = delegator;
667 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
668 if (appid == nullptr)
671 /* com.vendor.name -> name */
672 const char* name_token = strrchr(appid, '.');
673 if (name_token == nullptr)
680 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
681 const char* res_path = aul_get_app_resource_path();
682 if (res_path == nullptr) {
683 _E("Failed to get resource path");
687 return std::string(res_path) + PATH_LOCALE;
690 int AppCoreBase::OnSetI18n() {
691 char appid[PATH_MAX];
692 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
694 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
698 std::string name = impl_->GetAppName(appid);
702 std::string locale_dir = impl_->GetLocaleResourceDir();
703 if (locale_dir.empty())
706 return SetI18n(move(name), move(locale_dir));
709 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
710 int val = vconf_keynode_get_int(key);
711 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
712 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
713 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
717 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
722 if (__rotation.ref == 0) {
724 if (feature_ & FEATURE_CHARGER_STATUS) {
725 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
726 ChargerStatusChangedCb);
731 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
732 if (__rotation.ref == 0) {
733 if (feature_ & FEATURE_CHARGER_STATUS) {
734 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
735 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
736 ChargerStatusChangedCb, parent_);
737 if (__rotation.charger_status)
747 int AppCoreBase::OnSetEvent(IEvent::Type event) {
749 case IEvent::Type::LOW_BATTERY:
750 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
751 impl_->OnLowBatteryCb, this);
753 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
754 impl_->RegisterRotationChangedEvent();
756 case IEvent::Type::SUSPENDED_STATE_CHANGE:
765 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
767 case IEvent::Type::LOW_BATTERY:
768 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
769 impl_->OnLowBatteryCb);
771 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
772 impl_->UnregisterRotationChangedEvent();
774 case IEvent::Type::SUSPENDED_STATE_CHANGE:
783 int AppCoreBase::OnTrimMemory() {
784 int (*sqlite3_free_heap_memory)(int);
786 sqlite3_free_heap_memory = reinterpret_cast<
787 decltype(sqlite3_free_heap_memory)>(
788 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
789 if (sqlite3_free_heap_memory)
790 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
796 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
798 for (auto& ev : impl_->events_) {
799 if (ev->GetType() == event->GetType()) {
806 if (impl_->core_delegator_)
807 impl_->core_delegator_->OnSetEvent(event->GetType());
809 OnSetEvent(event->GetType());
812 impl_->events_.push_back(move(event));
815 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
817 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
818 if (event.get() == ptr.get()) {
828 void AppCoreBase::FlushMemory() {
829 if (impl_->core_delegator_)
830 impl_->core_delegator_->OnTrimMemory();
835 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
836 _D("[__SUSPEND__] flush case");
837 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
838 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
839 impl_->suspended_state_ = true;
843 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
845 throw std::runtime_error("invalid rotation state");
847 return __rotation.rm;
850 bool AppCoreBase::IsBgAllowed() {
851 return impl_->allowed_bg_;
854 bool AppCoreBase::IsSuspended() {
855 return impl_->suspended_state_;
858 void AppCoreBase::ToggleSuspendedState() {
859 impl_->suspended_state_ = !impl_->suspended_state_;
862 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
863 const std::string& lang) {
864 std::istringstream ss(lang);
865 std::list<std::string> li;
868 while (std::getline(ss, token, ':'))
874 void AppCoreBase::Impl::AppendDefaultLangs(std::set<std::string>& lang_set) {
875 lang_set.insert({"en_US", "en_GB", "en"});
878 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
880 if (cstr == nullptr || delim == nullptr)
883 auto str = std::string(cstr);
884 auto idx = str.find(delim);
885 return str.substr(0, idx);
888 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
889 if (locale_dir_.empty())
892 DIR* dp = opendir(locale_dir_.c_str());
896 std::map<std::string, std::set<std::string>> table;
897 struct dirent *dentry;
898 while ((dentry = readdir(dp)) != nullptr) {
899 if (!strcmp(dentry->d_name, ".") ||
900 !strcmp(dentry->d_name, ".."))
903 std::string buf = locale_dir_ + "/" + dentry->d_name;
904 struct stat stat_buf;
905 int ret = stat(buf.c_str(), &stat_buf);
906 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
909 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
910 if (parent_lang.empty()) {
915 table[parent_lang].insert(dentry->d_name);
922 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
923 std::set<std::string>& lang_set,
924 std::map<std::string, std::set<std::string>>& table) {
928 lang_set.insert(lang);
929 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
930 if (extract_lang.empty())
933 if (lang_set.find(extract_lang) != lang_set.end())
936 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
937 if (parent_lang.empty())
940 if (table.find(parent_lang) == table.end())
943 auto it = table[parent_lang].find(extract_lang);
944 if (it != table[parent_lang].end()) {
945 lang_set.insert(move(*it));
946 table[parent_lang].erase(it);
950 it = table[parent_lang].find(parent_lang);
951 if (it != table[parent_lang].end()) {
952 lang_set.insert(move(*it));
953 table[parent_lang].erase(parent_lang);
957 if (!table[parent_lang].empty()) {
958 auto i = table[parent_lang].begin();
959 lang_set.insert(move(*i));
960 table[parent_lang].erase(i);
964 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
965 std::list<std::string> l = SplitLanguage(lang);
969 auto table = GetLangTable();
973 std::set<std::string> lang_set {};
975 AppendLangs(i, lang_set, table);
977 AppendDefaultLangs(lang_set);
979 for (auto& i : lang_set) {
989 void AppCoreBase::Impl::UpdateLang() {
990 char* lang = vconf_get_str(VCONFKEY_LANGSET);
994 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
995 std::string language = GetLanguage(lang);
996 if (!language.empty()) {
997 _D("*****language(%s)", language.c_str());
998 setenv("LANGUAGE", language.c_str(), 1);
1000 setenv("LANGUAGE", lang, 1);
1002 setenv("LANG", lang, 1);
1003 setenv("LC_MESSAGES", lang, 1);
1004 setenv("LC_ALL", lang, 1);
1005 char* r = setlocale(LC_ALL, "");
1007 r = setlocale(LC_ALL, "en_US.UTF-8");
1009 _D("*****appcore setlocale=%s\n", r);
1011 _D("*****appcore setlocale=\"C\"");
1012 setenv("LC_ALL", "C", 1);
1013 r = setlocale(LC_ALL, "");
1015 _E("failed to setlocale");
1020 void AppCoreBase::Impl::UpdateRegion() {
1021 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1022 if (region == nullptr)
1025 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1026 setenv("LC_CTYPE", region, 1);
1027 setenv("LC_NUMERIC", region, 1);
1028 setenv("LC_TIME", region, 1);
1029 setenv("LC_COLLATE", region, 1);
1030 setenv("LC_MONETARY", region, 1);
1031 setenv("LC_PAPER", region, 1);
1032 setenv("LC_NAME", region, 1);
1033 setenv("LC_ADDRESS", region, 1);
1034 setenv("LC_TELEPHONE", region, 1);
1035 setenv("LC_MEASUREMENT", region, 1);
1036 setenv("LC_IDENTIFICATION", region, 1);
1037 char* r = setlocale(LC_ALL, "");
1039 _D("*****appcore setlocale=%s\n", r);
1041 _D("*****appcore setlocale=\"C\"");
1042 setenv("LC_ALL", "C", 1);
1043 r = setlocale(LC_ALL, "");
1045 _E("failed to setlocale");
1049 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1050 if (domain_name.empty()) {
1055 if (!dir_name.empty())
1056 impl_->locale_dir_ = dir_name;
1058 impl_->UpdateLang();
1059 impl_->UpdateRegion();
1061 char* r = setlocale(LC_ALL, "");
1062 /* if locale is not set properly, try to set "en_US" again */
1064 r = setlocale(LC_ALL, "en_US.UTF-8");
1066 _E("appcore: setlocale() error");
1067 _D("*****appcore setlocale=\"C\"");
1068 setenv("LC_ALL", "C", 1);
1069 r = setlocale(LC_ALL, "");
1071 _E("failed to setlocale");
1076 _D("*****appcore setlocale=%s\n", r);
1078 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1080 _E("appcore: bindtextdomain() error");
1082 r = textdomain(domain_name.c_str());
1084 _E("appcore: textdomain() error");
1089 void AppCoreBase::Exit() {
1090 aul_status_update(STATUS_DYING);
1091 if (impl_->loop_delegator_)
1092 impl_->loop_delegator_->OnLoopExit();
1097 void AppCoreBase::AddSuspendTimer() {
1098 impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1099 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1100 base->FlushMemory();
1105 void AppCoreBase::RemoveSuspendTimer() {
1106 if (impl_->tid_ > 0) {
1107 GLib::SourceRemove(impl_->tid_);
1112 void AppCoreBase::SetDisplayState(DisplayState state) {
1113 __display_state = state;
1116 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1117 return __display_state;
1120 int AppCoreBase::EnableWatchdog() {
1121 _I("[__APPCORE_WATCHDOG__] enable");
1122 return aul_watchdog_enable();
1125 int AppCoreBase::DisableWatchdog() {
1126 _I("[__APPCORE_WATCHDOG__] disable");
1127 return aul_watchdog_disable();
1130 int AppCoreBase::KickWatchdog() {
1131 _I("[__APPCORE_WATCHDOG__] kick");
1132 return aul_watchdog_kick();
1135 void AppCoreBase::Run(int argc, char** argv) {
1140 void AppCoreBase::Init(int argc, char** argv) {
1142 impl_->suspended_state_ = false;
1143 impl_->allowed_bg_ = false;
1144 impl_->argc_ = argc;
1145 impl_->argv_ = argv;
1146 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1147 if (impl_->loop_delegator_)
1148 impl_->loop_delegator_->OnLoopInit(argc, argv);
1150 OnLoopInit(argc, argv);
1151 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1153 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1154 GLib::IdleAdd(Impl::InitSuspendCb, this);
1156 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1157 if (!impl_->dirty_) {
1158 impl_->dirty_ = true;
1160 for (auto& e : impl_->events_) {
1161 if (impl_->core_delegator_)
1162 impl_->core_delegator_->OnSetEvent(e->GetType());
1164 OnSetEvent(e->GetType());
1167 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1169 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1170 impl_->VerifyLanguage();
1171 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1173 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1174 impl_->SetDefaultEvents();
1175 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1177 if (impl_->core_delegator_)
1178 impl_->core_delegator_->OnSetI18n();
1182 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1184 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1186 if (impl_->core_delegator_)
1187 create = impl_->core_delegator_->OnCreate();
1189 create = OnCreate();
1190 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1192 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1196 if (impl_->loop_delegator_)
1197 impl_->loop_delegator_->OnLoopRun();
1202 void AppCoreBase::Fini() {
1206 void AppCoreBase::Dispose() {
1207 aul_status_update(STATUS_DYING);
1209 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1211 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1212 if (impl_->core_delegator_)
1213 impl_->core_delegator_->OnTerminate();
1216 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1218 for (auto& e : impl_->events_) {
1219 if (impl_->core_delegator_)
1220 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1222 OnUnsetEvent(e->GetType());
1225 impl_->UnsetDefaultEvents();
1227 GLib::SourceRemove(impl_->sid_);
1231 RemoveSuspendTimer();
1232 impl_->dirty_ = false;
1233 if (impl_->loop_delegator_)
1234 impl_->loop_delegator_->OnLoopFinish();
1239 void AppCoreBase::SetFeature(int feature) {
1240 impl_->feature_ = feature;
1243 int AppCoreBase::GetFeature() const {
1244 return impl_->feature_;
1247 } // namespace tizen_cpp