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" void aul_finalize();
62 TizenProfile TizenProfileGet() {
63 static TizenProfile profile = TizenProfile::Unknown;
64 if (__builtin_expect(profile != TizenProfile::Unknown, 1))
67 char* profile_name = nullptr;
68 system_info_get_platform_string("http://tizen.org/feature/profile",
70 if (profile_name == nullptr)
73 switch (*profile_name) {
76 profile = TizenProfile::Mobile;
80 profile = TizenProfile::Wearable;
84 profile = TizenProfile::Tv;
88 profile = TizenProfile::Ivi;
91 profile = TizenProfile::Common;
99 constexpr const char PATH_LOCALE[] = "locale";
100 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
101 constexpr const char RESOURCED_FREEZER_PATH[] =
102 "/Org/Tizen/ResourceD/Freezer";
103 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
104 "org.tizen.resourced.freezer";
105 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
112 tizen_cpp::AppCoreBase::RotationState rm;
118 GDBusConnection* __bus;
119 guint __suspend_dbus_handler_initialized;
120 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
124 class AppCoreBase::EventBase::Impl {
126 friend class AppCoreBase;
127 Type type_ = IEvent::Type::START;
128 std::string str_val_;
132 class AppCoreBase::Impl {
134 explicit Impl(AppCoreBase* parent) : parent_(parent) {
135 if (TizenProfileGet() & TizenProfile::Wearable)
136 feature_ |= FEATURE_CHARGER_STATUS;
137 if (!(TizenProfileGet() & TizenProfile::Tv))
138 feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
142 void UnregisterRotationChangedEvent();
143 void RegisterRotationChangedEvent();
144 std::string GetAppName(const char* appid);
145 std::string GetLocaleResourceDir();
148 std::list<std::string> SplitLanguage(const std::string& lang);
149 std::string GetLanguage(std::string lang);
150 void AppendDefaultLangs(std::set<std::string>& lang_set);
151 std::string GetStringBefore(const char* str, const char* delim);
152 std::map<std::string, std::set<std::string>> GetLangTable();
153 void AppendLangs(const std::string& lang, std::set<std::string>& lang_set,
154 std::map<std::string, std::set<std::string>>& table);
156 void OnFreezerSignal();
159 void InvokeCallback(T event, IEvent::Type type) {
160 for (auto& i : events_) {
161 if (i->GetType() != type)
164 if (i->GetVal(event) != event ||
165 type == IEvent::Type::START ||
166 type == IEvent::Type::UPDATE_REQUESTED) {
173 static void InitSuspendDbusHandler(gpointer data);
174 static gboolean InitSuspendCb(gpointer data);
175 static gboolean InvokeLangChangeCb(gpointer data);
176 static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
177 const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
178 static void OnLowBatteryCb(keynode_t* key, void* data);
179 static void LockCb(keynode_t* node, void* user_data);
180 static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
181 sensor_data_t* data, void* user_data);
182 static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
183 static void LanguageChangeCb(keynode_t* key, void* data);
184 static void RegionChangeCb(keynode_t* key, void* data);
185 static void LowMemoryCb(keynode_t* key, void* data);
188 RotationState GetRm(sensor_data_t data);
189 void VerifyLanguage();
190 void SetDefaultEvents();
191 void UnsetDefaultEvents();
194 friend class AppCoreBase;
195 AppCoreBase* parent_ = nullptr;
198 char** argv_ = nullptr;
199 bool suspended_state_ = false;
200 bool allowed_bg_ = false;
202 unsigned int tid_ = 0;
203 std::list<std::shared_ptr<EventBase>> events_;
204 std::string locale_dir_;
207 IAppCore* core_delegator_ = nullptr;
208 IMainLoop* loop_delegator_ = nullptr;
211 AppCoreBase::EventBase::EventBase(Type type)
212 : impl_(std::make_unique<EventBase::Impl>()) {
216 AppCoreBase::EventBase::~EventBase() = default;
218 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
222 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
223 return impl_->str_val_;
226 int AppCoreBase::EventBase::GetVal(int cur) const {
230 void AppCoreBase::EventBase::SetVal(std::string val) {
231 impl_->str_val_ = std::move(val);
234 void AppCoreBase::EventBase::SetVal(int val) {
235 impl_->val_ = std::move(val);
238 AppCoreBase::AppCoreBase() : impl_(std::make_unique<AppCoreBase::Impl>(this)) {}
239 AppCoreBase::~AppCoreBase() = default;
241 void AppCoreBase::Impl::ChangeLang() {
242 const char* lang = getenv("LANG");
246 InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
249 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
250 impl_->InvokeCallback(event, type);
253 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
254 impl_->InvokeCallback(event, type);
257 void AppCoreBase::Impl::OnFreezerSignal() {
258 if (!allowed_bg_ && suspended_state_) {
259 parent_->RemoveSuspendTimer();
260 InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
261 IEvent::Type::SUSPENDED_STATE_CHANGE);
262 suspended_state_ = false;
263 parent_->AddSuspendTimer();
267 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
268 if (data.value_count <= 0) {
269 _E("Failed to get sensor data");
270 return ROTATION_UNKNOWN;
273 int event = data.values[0];
275 case AUTO_ROTATION_DEGREE_0:
276 return ROTATION_PORTRAIT_NORMAL;
277 case AUTO_ROTATION_DEGREE_90:
278 return ROTATION_LANDSCAPE_NORMAL;
279 case AUTO_ROTATION_DEGREE_180:
280 return ROTATION_PORTRAIT_REVERSE;
281 case AUTO_ROTATION_DEGREE_270:
282 return ROTATION_LANDSCAPE_REVERSE;
284 return ROTATION_UNKNOWN;
288 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
289 if (__suspend_dbus_handler_initialized)
292 if (__bus == nullptr) {
293 GError* err = nullptr;
294 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
295 if (__bus == nullptr) {
296 _E("Failed to connect to the D-BUS daemon: %s", err->message);
302 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
303 __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
304 RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
305 ReceiveSuspendSignalCb, data, nullptr);
307 if (__suspend_dbus_handler_initialized == 0) {
308 _E("g_dbus_connection_signal_subscribe() is failed.");
312 _D("[__SUSPEND__] suspend signal initialized");
315 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
316 InitSuspendDbusHandler(data);
317 return G_SOURCE_REMOVE;
320 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
321 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
322 base->impl_->sid_ = 0;
323 base->impl_->ChangeLang();
324 return G_SOURCE_REMOVE;
327 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
328 const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
329 gpointer user_data) {
330 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
333 g_variant_get(parameters, "(ii)", &status, &pid);
334 if (pid == getpid() && status == 0) {
335 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
336 base->impl_->OnFreezerSignal();
341 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
342 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
343 if (base->impl_->sid_) {
344 g_source_remove(base->impl_->sid_);
345 base->impl_->sid_ = 0;
348 char* val = vconf_keynode_get_str(key);
352 base->impl_->UpdateLang();
353 base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
356 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
357 const char* name = vconf_keynode_get_name(key);
361 if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
362 strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
365 char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
368 std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
370 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
371 base->impl_->UpdateRegion();
372 base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
375 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
376 int val = vconf_keynode_get_int(key);
377 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
378 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
379 base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
384 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
386 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
387 if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
388 __rotation.charger_status = vconf_keynode_get_int(keynode);
389 if (__rotation.ref) {
390 if (__rotation.charger_status) {
391 base->impl_->InitRotation();
393 base->impl_->FiniRotation();
397 _D("charger status(%d)", __rotation.charger_status);
401 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
402 AppCoreBase::RotationState rm;
403 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
405 __rotation.lock = !vconf_keynode_get_bool(node);
406 if (__rotation.lock) {
407 _D("Rotation locked");
408 rm = ROTATION_PORTRAIT_NORMAL;
410 _D("Rotation unlocked");
412 bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
414 _E("Failed to get sensor data");
418 rm = base->impl_->GetRm(data);
419 if (rm == ROTATION_UNKNOWN) {
425 if (__rotation.rm == rm)
428 _D("Rotation: %d -> %d", __rotation.rm, rm);
430 base->impl_->InvokeCallback(__rotation.rm,
431 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
434 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
435 unsigned int event_type, sensor_data_t* data, void* user_data) {
442 if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
445 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
446 AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
447 if (rm == ROTATION_UNKNOWN) {
452 _D("Rotation: %d -> %d", __rotation.rm, rm);
454 base->impl_->InvokeCallback(__rotation.rm,
455 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
458 void AppCoreBase::Impl::InitRotation() {
459 if (__rotation.initialized)
462 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
463 __rotation.conn = sensord_connect(sensor);
464 if (__rotation.conn < 0) {
465 _E("Failed to connect sensord");
469 bool r = sensord_register_event(__rotation.conn,
470 AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
471 AutoRotationChangedCb, parent_);
473 _E("Failed to register auto rotation change event");
474 sensord_disconnect(__rotation.conn);
478 r = sensord_start(__rotation.conn, 0);
480 _E("Failed to start sensord");
481 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
482 sensord_disconnect(__rotation.conn);
487 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
488 vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
491 __rotation.lock = !lock;
492 __rotation.initialized = true;
495 void AppCoreBase::Impl::FiniRotation() {
496 if (!__rotation.initialized)
499 vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
500 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
501 sensord_stop(__rotation.conn);
502 sensord_disconnect(__rotation.conn);
505 __rotation.initialized = false;
508 void AppCoreBase::Impl::VerifyLanguage() {
509 const char* env_lang = getenv("LANG");
510 if (env_lang == nullptr)
513 char* lang = vconf_get_str(VCONFKEY_LANGSET);
517 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
519 if (strcmp(env_lang, lang) != 0) {
520 _I("LANG(%s), LANGSET(%s)", env_lang, lang);
521 sid_ = g_idle_add(InvokeLangChangeCb, parent_);
525 void AppCoreBase::Impl::SetDefaultEvents() {
526 vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
527 int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
530 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
534 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
537 void AppCoreBase::Impl::UnsetDefaultEvents() {
538 vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
539 int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
541 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
543 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
546 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
549 _D("[APP %d] AUL event: AUL_START", getpid());
550 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
551 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
552 if (bg == "ALLOWED_BG") {
553 _D("[__SUSPEND__] allowed background");
554 impl_->allowed_bg_ = true;
555 RemoveSuspendTimer();
559 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
560 if (impl_->core_delegator_)
561 impl_->core_delegator_->OnControl(std::move(b));
563 OnControl(std::move(b));
564 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
567 _D("[APP %d] AUL event: AUL_RESUME", getpid());
568 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
569 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
570 if (bg == "ALLOWED_BG") {
571 _D("[__SUSPEND__] allowed background");
572 impl_->allowed_bg_ = true;
573 RemoveSuspendTimer();
578 _D("[APP %d] AUL event: AUL_TERMINATE", getpid());
579 aul_status_update(STATUS_DYING);
580 if (!impl_->allowed_bg_)
581 RemoveSuspendTimer();
583 if (impl_->loop_delegator_)
584 impl_->loop_delegator_->OnLoopExit();
588 case AUL_TERMINATE_INST:
589 case AUL_TERMINATE_BG_INST:
590 case AUL_TERMINATE_BGAPP:
591 _D("[APP %d] AUL event: %d", getpid(), type);
592 if (!impl_->allowed_bg_)
593 RemoveSuspendTimer();
596 _D("[APP %d] AUL event: AUL_WAKE", getpid());
597 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
598 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
599 RemoveSuspendTimer();
600 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
601 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
602 impl_->suspended_state_ = false;
607 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
608 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
609 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
610 RemoveSuspendTimer();
615 case AUL_UPDATE_REQUESTED:
616 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
617 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
620 _D("[APP %d] AUL event: %d", getpid(), type);
628 int AppCoreBase::OnCreate() {
629 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
630 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
631 if (base->impl_->core_delegator_) {
632 return base->impl_->core_delegator_->OnReceive(type,
633 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
635 return base->OnReceive(type,
636 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
638 if (ret < 0 && ret != AUL_R_ECANCELED) {
639 _E("aul_launch_init() is failed. error(%d)", ret);
643 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
645 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
652 int AppCoreBase::OnControl(tizen_base::Bundle b) {
656 int AppCoreBase::OnTerminate() {
661 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
662 impl_->core_delegator_ = delegator;
665 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
666 impl_->loop_delegator_ = delegator;
669 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
670 if (appid == nullptr)
673 /* com.vendor.name -> name */
674 const char* name_token = strrchr(appid, '.');
675 if (name_token == nullptr)
682 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
683 const char* res_path = aul_get_app_resource_path();
684 if (res_path == nullptr) {
685 _E("Failed to get resource path");
689 std::string path = std::string(res_path) + PATH_LOCALE;
690 if (access(path.c_str(), R_OK) != 0)
691 _W("%s does not exist", path.c_str());
696 int AppCoreBase::OnSetI18n() {
697 char appid[PATH_MAX];
698 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
700 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
704 std::string name = impl_->GetAppName(appid);
708 std::string locale_dir = impl_->GetLocaleResourceDir();
709 if (locale_dir.empty())
712 return SetI18n(move(name), move(locale_dir));
715 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
716 int val = vconf_keynode_get_int(key);
717 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
718 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
719 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
723 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
728 if (__rotation.ref == 0) {
730 if (feature_ & FEATURE_CHARGER_STATUS) {
731 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
732 ChargerStatusChangedCb);
737 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
738 if (__rotation.ref == 0) {
739 if (feature_ & FEATURE_CHARGER_STATUS) {
740 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
741 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
742 ChargerStatusChangedCb, parent_);
743 if (__rotation.charger_status)
753 int AppCoreBase::OnSetEvent(IEvent::Type event) {
755 case IEvent::Type::LOW_BATTERY:
756 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
757 impl_->OnLowBatteryCb, this);
759 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
760 impl_->RegisterRotationChangedEvent();
762 case IEvent::Type::SUSPENDED_STATE_CHANGE:
771 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
773 case IEvent::Type::LOW_BATTERY:
774 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
775 impl_->OnLowBatteryCb);
777 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
778 impl_->UnregisterRotationChangedEvent();
780 case IEvent::Type::SUSPENDED_STATE_CHANGE:
789 int AppCoreBase::OnTrimMemory() {
790 int (*sqlite3_free_heap_memory)(int);
792 sqlite3_free_heap_memory = reinterpret_cast<
793 decltype(sqlite3_free_heap_memory)>(
794 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
795 if (sqlite3_free_heap_memory)
796 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
802 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
804 for (auto& ev : impl_->events_) {
805 if (ev->GetType() == event->GetType()) {
812 if (impl_->core_delegator_)
813 impl_->core_delegator_->OnSetEvent(event->GetType());
815 OnSetEvent(event->GetType());
818 impl_->events_.push_back(move(event));
821 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
823 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
824 if (event.get() == ptr.get()) {
834 void AppCoreBase::FlushMemory() {
835 if (impl_->core_delegator_)
836 impl_->core_delegator_->OnTrimMemory();
841 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
842 _D("[__SUSPEND__] flush case");
843 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
844 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
845 impl_->suspended_state_ = true;
849 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
851 throw std::runtime_error("invalid rotation state");
853 return __rotation.rm;
856 bool AppCoreBase::IsBgAllowed() {
857 return impl_->allowed_bg_;
860 bool AppCoreBase::IsSuspended() {
861 return impl_->suspended_state_;
864 void AppCoreBase::ToggleSuspendedState() {
865 impl_->suspended_state_ = !impl_->suspended_state_;
868 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
869 const std::string& lang) {
870 std::istringstream ss(lang);
871 std::list<std::string> li;
874 while (std::getline(ss, token, ':'))
880 void AppCoreBase::Impl::AppendDefaultLangs(std::set<std::string>& lang_set) {
881 lang_set.insert({"en_US", "en_GB", "en"});
884 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
886 if (cstr == nullptr || delim == nullptr)
889 auto str = std::string(cstr);
890 auto idx = str.find(delim);
891 return str.substr(0, idx);
894 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
895 if (locale_dir_.empty())
898 DIR* dp = opendir(locale_dir_.c_str());
902 std::map<std::string, std::set<std::string>> table;
903 struct dirent *dentry;
904 while ((dentry = readdir(dp)) != nullptr) {
905 if (!strcmp(dentry->d_name, ".") ||
906 !strcmp(dentry->d_name, ".."))
909 std::string buf = locale_dir_ + "/" + dentry->d_name;
910 struct stat stat_buf;
911 int ret = stat(buf.c_str(), &stat_buf);
912 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
915 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
916 if (parent_lang.empty()) {
921 table[parent_lang].insert(dentry->d_name);
928 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
929 std::set<std::string>& lang_set,
930 std::map<std::string, std::set<std::string>>& table) {
934 lang_set.insert(lang);
935 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
936 if (extract_lang.empty())
939 if (lang_set.find(extract_lang) != lang_set.end())
942 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
943 if (parent_lang.empty())
946 if (table.find(parent_lang) == table.end())
949 auto it = table[parent_lang].find(extract_lang);
950 if (it != table[parent_lang].end()) {
951 lang_set.insert(move(*it));
952 table[parent_lang].erase(it);
956 it = table[parent_lang].find(parent_lang);
957 if (it != table[parent_lang].end()) {
958 lang_set.insert(move(*it));
959 table[parent_lang].erase(parent_lang);
963 if (!table[parent_lang].empty()) {
964 auto i = table[parent_lang].begin();
965 lang_set.insert(move(*i));
966 table[parent_lang].erase(i);
970 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
971 std::list<std::string> l = SplitLanguage(lang);
975 auto table = GetLangTable();
979 std::set<std::string> lang_set {};
981 AppendLangs(i, lang_set, table);
983 AppendDefaultLangs(lang_set);
985 for (auto& i : lang_set) {
997 void AppCoreBase::Impl::UpdateLang() {
998 char* lang = vconf_get_str(VCONFKEY_LANGSET);
1002 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1003 std::string language = GetLanguage(lang);
1004 if (!language.empty()) {
1005 _D("*****language(%s)", language.c_str());
1006 setenv("LANGUAGE", language.c_str(), 1);
1008 setenv("LANGUAGE", lang, 1);
1010 setenv("LANG", lang, 1);
1011 setenv("LC_MESSAGES", lang, 1);
1012 setenv("LC_ALL", lang, 1);
1013 char* r = setlocale(LC_ALL, "");
1015 r = setlocale(LC_ALL, "en_US.UTF-8");
1017 _D("*****appcore setlocale=%s\n", r);
1019 _D("*****appcore setlocale=\"C\"");
1020 setenv("LC_ALL", "C", 1);
1021 r = setlocale(LC_ALL, "");
1023 _E("failed to setlocale");
1028 void AppCoreBase::Impl::UpdateRegion() {
1029 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1030 if (region == nullptr)
1033 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1034 setenv("LC_CTYPE", region, 1);
1035 setenv("LC_NUMERIC", region, 1);
1036 setenv("LC_TIME", region, 1);
1037 setenv("LC_COLLATE", region, 1);
1038 setenv("LC_MONETARY", region, 1);
1039 setenv("LC_PAPER", region, 1);
1040 setenv("LC_NAME", region, 1);
1041 setenv("LC_ADDRESS", region, 1);
1042 setenv("LC_TELEPHONE", region, 1);
1043 setenv("LC_MEASUREMENT", region, 1);
1044 setenv("LC_IDENTIFICATION", region, 1);
1045 char* r = setlocale(LC_ALL, "");
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");
1057 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1058 if (domain_name.empty()) {
1063 if (!dir_name.empty())
1064 impl_->locale_dir_ = dir_name;
1066 impl_->UpdateLang();
1067 impl_->UpdateRegion();
1069 char* r = setlocale(LC_ALL, "");
1070 /* if locale is not set properly, try to set "en_US" again */
1072 r = setlocale(LC_ALL, "en_US.UTF-8");
1074 _E("appcore: setlocale() error");
1075 _D("*****appcore setlocale=\"C\"");
1076 setenv("LC_ALL", "C", 1);
1077 r = setlocale(LC_ALL, "");
1079 _E("failed to setlocale");
1084 _D("*****appcore setlocale=%s\n", r);
1086 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1088 _E("appcore: bindtextdomain() error");
1090 r = textdomain(domain_name.c_str());
1092 _E("appcore: textdomain() error");
1097 void AppCoreBase::Exit() {
1098 aul_status_update(STATUS_DYING);
1099 if (impl_->loop_delegator_)
1100 impl_->loop_delegator_->OnLoopExit();
1105 void AppCoreBase::AddSuspendTimer() {
1106 impl_->tid_ = g_timeout_add_seconds(5, [](gpointer data) -> gboolean {
1107 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1108 base->FlushMemory();
1113 void AppCoreBase::RemoveSuspendTimer() {
1114 if (impl_->tid_ > 0) {
1115 g_source_remove(impl_->tid_);
1120 void AppCoreBase::SetDisplayState(DisplayState state) {
1121 __display_state = state;
1124 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1125 return __display_state;
1128 int AppCoreBase::EnableWatchdog() {
1129 _I("[__APPCORE_WATCHDOG__] enable");
1130 return aul_watchdog_enable();
1133 int AppCoreBase::DisableWatchdog() {
1134 _I("[__APPCORE_WATCHDOG__] disable");
1135 return aul_watchdog_disable();
1138 int AppCoreBase::KickWatchdog() {
1139 _I("[__APPCORE_WATCHDOG__] kick");
1140 return aul_watchdog_kick();
1143 void AppCoreBase::Run(int argc, char** argv) {
1148 void AppCoreBase::Init(int argc, char** argv) {
1150 impl_->suspended_state_ = false;
1151 impl_->allowed_bg_ = false;
1152 impl_->argc_ = argc;
1153 impl_->argv_ = argv;
1154 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1155 if (impl_->loop_delegator_)
1156 impl_->loop_delegator_->OnLoopInit(argc, argv);
1158 OnLoopInit(argc, argv);
1159 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1161 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1162 g_idle_add(Impl::InitSuspendCb, this);
1164 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1165 if (!impl_->dirty_) {
1166 impl_->dirty_ = true;
1168 for (auto& e : impl_->events_) {
1169 if (impl_->core_delegator_)
1170 impl_->core_delegator_->OnSetEvent(e->GetType());
1172 OnSetEvent(e->GetType());
1175 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1177 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1178 impl_->VerifyLanguage();
1179 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1181 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1182 impl_->SetDefaultEvents();
1183 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1185 if (impl_->core_delegator_)
1186 impl_->core_delegator_->OnSetI18n();
1190 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1192 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1194 if (impl_->core_delegator_)
1195 create = impl_->core_delegator_->OnCreate();
1197 create = OnCreate();
1198 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1200 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1204 if (impl_->loop_delegator_)
1205 impl_->loop_delegator_->OnLoopRun();
1210 void AppCoreBase::Fini() {
1214 void AppCoreBase::Dispose() {
1215 aul_status_update(STATUS_DYING);
1217 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1219 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1220 if (impl_->core_delegator_)
1221 impl_->core_delegator_->OnTerminate();
1224 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1226 for (auto& e : impl_->events_) {
1227 if (impl_->core_delegator_)
1228 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1230 OnUnsetEvent(e->GetType());
1233 impl_->UnsetDefaultEvents();
1235 g_source_remove(impl_->sid_);
1239 RemoveSuspendTimer();
1240 impl_->dirty_ = false;
1241 if (impl_->loop_delegator_)
1242 impl_->loop_delegator_->OnLoopFinish();
1247 void AppCoreBase::SetFeature(int feature) {
1248 impl_->feature_ = feature;
1251 int AppCoreBase::GetFeature() const {
1252 return impl_->feature_;
1255 } // namespace tizen_cpp