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/log_private.hh"
48 extern "C" int aul_is_initialized();
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 g_source_remove(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_ = g_idle_add(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();
584 if (impl_->loop_delegator_)
585 impl_->loop_delegator_->OnLoopExit();
589 case AUL_TERMINATE_INST:
590 case AUL_TERMINATE_BG_INST:
591 case AUL_TERMINATE_BGAPP:
592 _D("[APP %d] AUL event: %d", getpid(), type);
593 if (!impl_->allowed_bg_)
594 RemoveSuspendTimer();
597 _D("[APP %d] AUL event: AUL_WAKE", getpid());
598 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
599 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
600 RemoveSuspendTimer();
601 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
602 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
603 impl_->suspended_state_ = false;
608 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
609 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
610 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
611 RemoveSuspendTimer();
616 case AUL_UPDATE_REQUESTED:
617 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
618 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
621 _D("[APP %d] AUL event: %d", getpid(), type);
629 int AppCoreBase::OnCreate() {
630 if (aul_is_initialized()) {
631 _E("AUL is already initialized");
635 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
636 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
637 if (base->impl_->core_delegator_) {
638 return base->impl_->core_delegator_->OnReceive(type,
639 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
641 return base->OnReceive(type,
642 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
644 if (ret < 0 && ret != AUL_R_ECANCELED) {
645 _E("aul_launch_init() is failed. error(%d)", ret);
649 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
651 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
658 int AppCoreBase::OnControl(tizen_base::Bundle b) {
662 int AppCoreBase::OnTerminate() {
667 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
668 impl_->core_delegator_ = delegator;
671 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
672 impl_->loop_delegator_ = delegator;
675 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
676 if (appid == nullptr)
679 /* com.vendor.name -> name */
680 const char* name_token = strrchr(appid, '.');
681 if (name_token == nullptr)
688 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
689 const char* res_path = aul_get_app_resource_path();
690 if (res_path == nullptr) {
691 _E("Failed to get resource path");
695 std::string path = std::string(res_path) + PATH_LOCALE;
696 if (access(path.c_str(), R_OK) != 0)
697 _W("%s does not exist", path.c_str());
702 int AppCoreBase::OnSetI18n() {
703 char appid[PATH_MAX];
704 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
706 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
710 std::string name = impl_->GetAppName(appid);
714 std::string locale_dir = impl_->GetLocaleResourceDir();
715 if (locale_dir.empty())
718 return SetI18n(move(name), move(locale_dir));
721 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
722 int val = vconf_keynode_get_int(key);
723 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
724 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
725 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
729 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
734 if (__rotation.ref == 0) {
736 if (feature_ & FEATURE_CHARGER_STATUS) {
737 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
738 ChargerStatusChangedCb);
743 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
744 if (__rotation.ref == 0) {
745 if (feature_ & FEATURE_CHARGER_STATUS) {
746 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
747 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
748 ChargerStatusChangedCb, parent_);
749 if (__rotation.charger_status)
759 int AppCoreBase::OnSetEvent(IEvent::Type event) {
761 case IEvent::Type::LOW_BATTERY:
762 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
763 impl_->OnLowBatteryCb, this);
765 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
766 impl_->RegisterRotationChangedEvent();
768 case IEvent::Type::SUSPENDED_STATE_CHANGE:
777 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
779 case IEvent::Type::LOW_BATTERY:
780 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
781 impl_->OnLowBatteryCb);
783 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
784 impl_->UnregisterRotationChangedEvent();
786 case IEvent::Type::SUSPENDED_STATE_CHANGE:
795 int AppCoreBase::OnTrimMemory() {
796 int (*sqlite3_free_heap_memory)(int);
798 sqlite3_free_heap_memory = reinterpret_cast<
799 decltype(sqlite3_free_heap_memory)>(
800 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
801 if (sqlite3_free_heap_memory)
802 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
808 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
810 for (auto& ev : impl_->events_) {
811 if (ev->GetType() == event->GetType()) {
818 if (impl_->core_delegator_)
819 impl_->core_delegator_->OnSetEvent(event->GetType());
821 OnSetEvent(event->GetType());
824 impl_->events_.push_back(move(event));
827 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
829 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
830 if (event.get() == ptr.get()) {
840 void AppCoreBase::FlushMemory() {
841 if (impl_->core_delegator_)
842 impl_->core_delegator_->OnTrimMemory();
847 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
848 _D("[__SUSPEND__] flush case");
849 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
850 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
851 impl_->suspended_state_ = true;
855 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
857 throw std::runtime_error("invalid rotation state");
859 return __rotation.rm;
862 bool AppCoreBase::IsBgAllowed() {
863 return impl_->allowed_bg_;
866 bool AppCoreBase::IsSuspended() {
867 return impl_->suspended_state_;
870 void AppCoreBase::ToggleSuspendedState() {
871 impl_->suspended_state_ = !impl_->suspended_state_;
874 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
875 const std::string& lang) {
876 std::istringstream ss(lang);
877 std::list<std::string> li;
880 while (std::getline(ss, token, ':'))
886 void AppCoreBase::Impl::AppendDefaultLangs(std::set<std::string>& lang_set) {
887 lang_set.insert({"en_US", "en_GB", "en"});
890 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
892 if (cstr == nullptr || delim == nullptr)
895 auto str = std::string(cstr);
896 auto idx = str.find(delim);
897 return str.substr(0, idx);
900 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
901 if (locale_dir_.empty())
904 DIR* dp = opendir(locale_dir_.c_str());
908 std::map<std::string, std::set<std::string>> table;
909 struct dirent *dentry;
910 while ((dentry = readdir(dp)) != nullptr) {
911 if (!strcmp(dentry->d_name, ".") ||
912 !strcmp(dentry->d_name, ".."))
915 std::string buf = locale_dir_ + "/" + dentry->d_name;
916 struct stat stat_buf;
917 int ret = stat(buf.c_str(), &stat_buf);
918 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
921 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
922 if (parent_lang.empty()) {
927 table[parent_lang].insert(dentry->d_name);
934 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
935 std::set<std::string>& lang_set,
936 std::map<std::string, std::set<std::string>>& table) {
940 lang_set.insert(lang);
941 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
942 if (extract_lang.empty())
945 if (lang_set.find(extract_lang) != lang_set.end())
948 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
949 if (parent_lang.empty())
952 if (table.find(parent_lang) == table.end())
955 auto it = table[parent_lang].find(extract_lang);
956 if (it != table[parent_lang].end()) {
957 lang_set.insert(move(*it));
958 table[parent_lang].erase(it);
962 it = table[parent_lang].find(parent_lang);
963 if (it != table[parent_lang].end()) {
964 lang_set.insert(move(*it));
965 table[parent_lang].erase(parent_lang);
969 if (!table[parent_lang].empty()) {
970 auto i = table[parent_lang].begin();
971 lang_set.insert(move(*i));
972 table[parent_lang].erase(i);
976 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
977 std::list<std::string> l = SplitLanguage(lang);
981 auto table = GetLangTable();
985 std::set<std::string> lang_set {};
987 AppendLangs(i, lang_set, table);
989 AppendDefaultLangs(lang_set);
991 for (auto& i : lang_set) {
1003 void AppCoreBase::Impl::UpdateLang() {
1004 char* lang = vconf_get_str(VCONFKEY_LANGSET);
1005 if (lang == nullptr)
1008 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1009 std::string language = GetLanguage(lang);
1010 if (!language.empty()) {
1011 _D("*****language(%s)", language.c_str());
1012 setenv("LANGUAGE", language.c_str(), 1);
1014 setenv("LANGUAGE", lang, 1);
1016 setenv("LANG", lang, 1);
1017 setenv("LC_MESSAGES", lang, 1);
1018 setenv("LC_ALL", lang, 1);
1019 char* r = setlocale(LC_ALL, "");
1021 r = setlocale(LC_ALL, "en_US.UTF-8");
1023 _D("*****appcore setlocale=%s\n", r);
1025 _D("*****appcore setlocale=\"C\"");
1026 setenv("LC_ALL", "C", 1);
1027 r = setlocale(LC_ALL, "");
1029 _E("failed to setlocale");
1034 void AppCoreBase::Impl::UpdateRegion() {
1035 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1036 if (region == nullptr)
1039 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1040 setenv("LC_CTYPE", region, 1);
1041 setenv("LC_NUMERIC", region, 1);
1042 setenv("LC_TIME", region, 1);
1043 setenv("LC_COLLATE", region, 1);
1044 setenv("LC_MONETARY", region, 1);
1045 setenv("LC_PAPER", region, 1);
1046 setenv("LC_NAME", region, 1);
1047 setenv("LC_ADDRESS", region, 1);
1048 setenv("LC_TELEPHONE", region, 1);
1049 setenv("LC_MEASUREMENT", region, 1);
1050 setenv("LC_IDENTIFICATION", region, 1);
1051 char* r = setlocale(LC_ALL, "");
1053 _D("*****appcore setlocale=%s\n", r);
1055 _D("*****appcore setlocale=\"C\"");
1056 setenv("LC_ALL", "C", 1);
1057 r = setlocale(LC_ALL, "");
1059 _E("failed to setlocale");
1063 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1064 if (domain_name.empty()) {
1069 if (!dir_name.empty())
1070 impl_->locale_dir_ = dir_name;
1072 impl_->UpdateLang();
1073 impl_->UpdateRegion();
1075 char* r = setlocale(LC_ALL, "");
1076 /* if locale is not set properly, try to set "en_US" again */
1078 r = setlocale(LC_ALL, "en_US.UTF-8");
1080 _E("appcore: setlocale() error");
1081 _D("*****appcore setlocale=\"C\"");
1082 setenv("LC_ALL", "C", 1);
1083 r = setlocale(LC_ALL, "");
1085 _E("failed to setlocale");
1090 _D("*****appcore setlocale=%s\n", r);
1092 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1094 _E("appcore: bindtextdomain() error");
1096 r = textdomain(domain_name.c_str());
1098 _E("appcore: textdomain() error");
1103 void AppCoreBase::Exit() {
1104 aul_status_update(STATUS_DYING);
1105 if (impl_->loop_delegator_)
1106 impl_->loop_delegator_->OnLoopExit();
1111 void AppCoreBase::AddSuspendTimer() {
1112 impl_->tid_ = g_timeout_add_seconds(5, [](gpointer data) -> gboolean {
1113 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1114 base->FlushMemory();
1119 void AppCoreBase::RemoveSuspendTimer() {
1120 if (impl_->tid_ > 0) {
1121 g_source_remove(impl_->tid_);
1126 void AppCoreBase::SetDisplayState(DisplayState state) {
1127 __display_state = state;
1130 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1131 return __display_state;
1134 int AppCoreBase::EnableWatchdog() {
1135 _I("[__APPCORE_WATCHDOG__] enable");
1136 return aul_watchdog_enable();
1139 int AppCoreBase::DisableWatchdog() {
1140 _I("[__APPCORE_WATCHDOG__] disable");
1141 return aul_watchdog_disable();
1144 int AppCoreBase::KickWatchdog() {
1145 _I("[__APPCORE_WATCHDOG__] kick");
1146 return aul_watchdog_kick();
1149 void AppCoreBase::Run(int argc, char** argv) {
1154 void AppCoreBase::Init(int argc, char** argv) {
1156 impl_->suspended_state_ = false;
1157 impl_->allowed_bg_ = false;
1158 impl_->argc_ = argc;
1159 impl_->argv_ = argv;
1160 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1161 if (impl_->loop_delegator_)
1162 impl_->loop_delegator_->OnLoopInit(argc, argv);
1164 OnLoopInit(argc, argv);
1165 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1167 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1168 g_idle_add(Impl::InitSuspendCb, this);
1170 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1171 if (!impl_->dirty_) {
1172 impl_->dirty_ = true;
1174 for (auto& e : impl_->events_) {
1175 if (impl_->core_delegator_)
1176 impl_->core_delegator_->OnSetEvent(e->GetType());
1178 OnSetEvent(e->GetType());
1181 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1183 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1184 impl_->VerifyLanguage();
1185 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1187 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1188 impl_->SetDefaultEvents();
1189 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1191 if (impl_->core_delegator_)
1192 impl_->core_delegator_->OnSetI18n();
1196 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1198 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1200 if (impl_->core_delegator_)
1201 create = impl_->core_delegator_->OnCreate();
1203 create = OnCreate();
1204 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1206 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1210 if (impl_->loop_delegator_)
1211 impl_->loop_delegator_->OnLoopRun();
1216 void AppCoreBase::Fini() {
1220 void AppCoreBase::Dispose() {
1221 aul_status_update(STATUS_DYING);
1223 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1225 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1226 if (impl_->core_delegator_)
1227 impl_->core_delegator_->OnTerminate();
1230 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1232 for (auto& e : impl_->events_) {
1233 if (impl_->core_delegator_)
1234 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1236 OnUnsetEvent(e->GetType());
1239 impl_->UnsetDefaultEvents();
1241 g_source_remove(impl_->sid_);
1245 RemoveSuspendTimer();
1246 impl_->dirty_ = false;
1247 if (impl_->loop_delegator_)
1248 impl_->loop_delegator_->OnLoopFinish();
1253 void AppCoreBase::SetFeature(int feature) {
1254 impl_->feature_ = feature;
1257 int AppCoreBase::GetFeature() const {
1258 return impl_->feature_;
1261 } // namespace tizen_cpp