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>
27 #include <linux/limits.h>
30 #include <sensor_internal.h>
35 #include <sys/types.h>
36 #include <system_info.h>
51 #include "app-core-cpp/app_core_base.hh"
52 #include "common/glib_private.hh"
53 #include "common/log_private.hh"
55 extern "C" void aul_finalize();
58 AppCoreBase* AppCoreBase::context_ = nullptr;
62 constexpr const int BACKTRACE_BUFFER_SIZE = 128;
67 on_exit(OnExit, this);
71 static void OnExit(int status, void *user_data) {
75 char* buffer[BACKTRACE_BUFFER_SIZE];
76 int nptrs = backtrace(reinterpret_cast<void**>(buffer),
77 BACKTRACE_BUFFER_SIZE);
78 fprintf(stderr, "%s backtrace() returned %d addesses\n",
81 // To print numbers, we use backtrace_symbols() instead of backtrace_symbols_fd().
82 // If there is an issues related to the memory, we cannot use backtrace_symbols().
83 // backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
84 char** strings = backtrace_symbols(reinterpret_cast<void**>(buffer), nptrs);
85 if (strings == nullptr) {
86 perror("backtrace_symbols");
91 for (int i = 0; i < nptrs; ++i) {
92 dladdr(buffer[i], &info);
93 fprintf(stderr, "[%3d] %s %s\n",
94 i, info.dli_sname ? info.dli_sname : "?", strings[i]);
98 fprintf(stderr, "%s(%d) abort()\n", __FUNCTION__, __LINE__);
103 ExitHandler exit_handler;
114 TizenProfile TizenProfileGet() {
115 static TizenProfile profile = TizenProfile::Unknown;
116 if (__builtin_expect(profile != TizenProfile::Unknown, 1))
119 char* profile_name = nullptr;
120 system_info_get_platform_string("http://tizen.org/feature/profile",
122 if (profile_name == nullptr)
125 switch (*profile_name) {
128 profile = TizenProfile::Mobile;
132 profile = TizenProfile::Wearable;
136 profile = TizenProfile::Tv;
140 profile = TizenProfile::Ivi;
143 profile = TizenProfile::Common;
151 constexpr const char PATH_LOCALE[] = "locale";
152 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
153 constexpr const char RESOURCED_FREEZER_PATH[] =
154 "/Org/Tizen/ResourceD/Freezer";
155 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
156 "org.tizen.resourced.freezer";
157 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
164 tizen_cpp::AppCoreBase::RotationState rm;
170 GDBusConnection* __bus;
171 guint __suspend_dbus_handler_initialized;
172 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
176 class AppCoreBase::EventBase::Impl {
178 friend class AppCoreBase;
179 Type type_ = IEvent::Type::START;
180 std::string str_val_;
184 class AppCoreBase::Impl {
186 explicit Impl(AppCoreBase* parent) : parent_(parent) {
187 if (TizenProfileGet() & TizenProfile::Wearable)
188 feature_ |= FEATURE_CHARGER_STATUS;
189 if (!(TizenProfileGet() & TizenProfile::Tv))
190 feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
194 void UnregisterRotationChangedEvent();
195 void RegisterRotationChangedEvent();
196 std::string GetAppName(const char* appid);
197 std::string GetLocaleResourceDir();
200 std::list<std::string> SplitLanguage(const std::string& lang);
201 std::string GetLanguage(std::string lang);
202 void AppendDefaultLangs(std::vector<std::string>& lang_set);
203 std::string GetStringBefore(const char* str, const char* delim);
204 std::map<std::string, std::set<std::string>> GetLangTable();
205 void AppendLangs(const std::string& lang, std::vector<std::string>& lang_set,
206 std::map<std::string, std::set<std::string>>& table);
208 void OnFreezerSignal();
211 void InvokeCallback(T event, IEvent::Type type) {
212 for (auto& i : events_) {
213 if (i->GetType() != type)
216 if (i->GetVal(event) != event ||
217 type == IEvent::Type::START ||
218 type == IEvent::Type::UPDATE_REQUESTED) {
225 static void InitSuspendDbusHandler(gpointer data);
226 static gboolean InitSuspendCb(gpointer data);
227 static gboolean InvokeLangChangeCb(gpointer data);
228 static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
229 const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
230 static void OnLowBatteryCb(keynode_t* key, void* data);
231 static void LockCb(keynode_t* node, void* user_data);
232 static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
233 sensor_data_t* data, void* user_data);
234 static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
235 static void LanguageChangeCb(keynode_t* key, void* data);
236 static void RegionChangeCb(keynode_t* key, void* data);
237 static void LowMemoryCb(keynode_t* key, void* data);
240 RotationState GetRm(sensor_data_t data);
241 void VerifyLanguage();
242 void SetDefaultEvents();
243 void UnsetDefaultEvents();
246 friend class AppCoreBase;
247 AppCoreBase* parent_ = nullptr;
250 char** argv_ = nullptr;
251 bool suspended_state_ = false;
252 bool allowed_bg_ = false;
254 unsigned int tid_ = 0;
255 std::list<std::shared_ptr<EventBase>> events_;
256 std::string locale_dir_;
259 IAppCore* core_delegator_ = nullptr;
260 IMainLoop* loop_delegator_ = nullptr;
263 AppCoreBase::EventBase::EventBase(Type type)
264 : impl_(std::make_unique<EventBase::Impl>()) {
268 AppCoreBase::EventBase::~EventBase() = default;
270 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
274 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
275 return impl_->str_val_;
278 int AppCoreBase::EventBase::GetVal(int cur) const {
282 void AppCoreBase::EventBase::SetVal(std::string val) {
283 impl_->str_val_ = std::move(val);
286 void AppCoreBase::EventBase::SetVal(int val) {
287 impl_->val_ = std::move(val);
290 AppCoreBase::AppCoreBase()
291 : impl_(std::make_unique<AppCoreBase::Impl>(this)) {
292 if (context_ != nullptr) {
293 _E("Context is already initialized");
299 AppCoreBase::~AppCoreBase() {
304 AppCoreBase* AppCoreBase::GetContext() {
305 if (context_ == nullptr) {
306 _E("Context is not initialized.");
313 void AppCoreBase::Impl::ChangeLang() {
314 const char* lang = getenv("LANG");
318 InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
321 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
322 impl_->InvokeCallback(event, type);
325 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
326 impl_->InvokeCallback(event, type);
329 void AppCoreBase::Impl::OnFreezerSignal() {
330 if (!allowed_bg_ && suspended_state_) {
331 parent_->RemoveSuspendTimer();
332 InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
333 IEvent::Type::SUSPENDED_STATE_CHANGE);
334 suspended_state_ = false;
335 parent_->AddSuspendTimer();
339 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
340 if (data.value_count <= 0) {
341 _E("Failed to get sensor data");
342 return ROTATION_UNKNOWN;
345 int event = data.values[0];
347 case AUTO_ROTATION_DEGREE_0:
348 return ROTATION_PORTRAIT_NORMAL;
349 case AUTO_ROTATION_DEGREE_90:
350 return ROTATION_LANDSCAPE_NORMAL;
351 case AUTO_ROTATION_DEGREE_180:
352 return ROTATION_PORTRAIT_REVERSE;
353 case AUTO_ROTATION_DEGREE_270:
354 return ROTATION_LANDSCAPE_REVERSE;
356 return ROTATION_UNKNOWN;
360 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
361 if (__suspend_dbus_handler_initialized)
364 if (__bus == nullptr) {
365 GError* err = nullptr;
366 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
367 if (__bus == nullptr) {
368 _E("Failed to connect to the D-BUS daemon: %s", err->message);
374 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
375 __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
376 RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
377 ReceiveSuspendSignalCb, data, nullptr);
379 if (__suspend_dbus_handler_initialized == 0) {
380 _E("g_dbus_connection_signal_subscribe() is failed.");
384 _D("[__SUSPEND__] suspend signal initialized");
387 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
388 InitSuspendDbusHandler(data);
389 return G_SOURCE_REMOVE;
392 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
393 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
394 base->impl_->sid_ = 0;
395 base->impl_->ChangeLang();
396 return G_SOURCE_REMOVE;
399 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
400 const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
401 gpointer user_data) {
402 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
405 g_variant_get(parameters, "(ii)", &status, &pid);
406 if (pid == getpid() && status == 0) {
407 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
408 base->impl_->OnFreezerSignal();
413 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
414 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
415 if (base->impl_->sid_) {
416 GLib::SourceRemove(base->impl_->sid_);
417 base->impl_->sid_ = 0;
420 char* val = vconf_keynode_get_str(key);
424 base->impl_->UpdateLang();
425 base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
428 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
429 const char* name = vconf_keynode_get_name(key);
433 if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
434 strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
437 char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
440 std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
442 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
443 base->impl_->UpdateRegion();
444 base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
447 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
448 int val = vconf_keynode_get_int(key);
449 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
450 base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
451 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
455 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
457 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
458 if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
459 __rotation.charger_status = vconf_keynode_get_int(keynode);
460 if (__rotation.ref) {
461 if (__rotation.charger_status) {
462 base->impl_->InitRotation();
464 base->impl_->FiniRotation();
468 _D("charger status(%d)", __rotation.charger_status);
472 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
473 AppCoreBase::RotationState rm;
474 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
476 __rotation.lock = !vconf_keynode_get_bool(node);
477 if (__rotation.lock) {
478 _D("Rotation locked");
479 rm = ROTATION_PORTRAIT_NORMAL;
481 _D("Rotation unlocked");
483 bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
485 _E("Failed to get sensor data");
489 rm = base->impl_->GetRm(data);
490 if (rm == ROTATION_UNKNOWN) {
496 if (__rotation.rm == rm)
499 _D("Rotation: %d -> %d", __rotation.rm, rm);
501 base->impl_->InvokeCallback(__rotation.rm,
502 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
505 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
506 unsigned int event_type, sensor_data_t* data, void* user_data) {
513 if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
516 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
517 AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
518 if (rm == ROTATION_UNKNOWN) {
523 _D("Rotation: %d -> %d", __rotation.rm, rm);
525 base->impl_->InvokeCallback(__rotation.rm,
526 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
529 void AppCoreBase::Impl::InitRotation() {
530 if (__rotation.initialized)
533 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
534 __rotation.conn = sensord_connect(sensor);
535 if (__rotation.conn < 0) {
536 _E("Failed to connect sensord");
540 bool r = sensord_register_event(__rotation.conn,
541 AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
542 AutoRotationChangedCb, parent_);
544 _E("Failed to register auto rotation change event");
545 sensord_disconnect(__rotation.conn);
549 r = sensord_start(__rotation.conn, 0);
551 _E("Failed to start sensord");
552 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
553 sensord_disconnect(__rotation.conn);
558 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
559 vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
562 __rotation.lock = !lock;
563 __rotation.initialized = true;
566 void AppCoreBase::Impl::FiniRotation() {
567 if (!__rotation.initialized)
570 vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
571 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
572 sensord_stop(__rotation.conn);
573 sensord_disconnect(__rotation.conn);
576 __rotation.initialized = false;
579 void AppCoreBase::Impl::VerifyLanguage() {
580 const char* env_lang = getenv("LANG");
581 if (env_lang == nullptr)
584 char* lang = vconf_get_str(VCONFKEY_LANGSET);
588 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
590 if (strcmp(env_lang, lang) != 0) {
591 _I("LANG(%s), LANGSET(%s)", env_lang, lang);
592 sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
596 void AppCoreBase::Impl::SetDefaultEvents() {
597 vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
598 int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
601 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
605 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
608 void AppCoreBase::Impl::UnsetDefaultEvents() {
609 vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
610 int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
612 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
614 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
617 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
620 _D("[APP %d] AUL event: AUL_START", getpid());
621 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
622 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
623 if (bg == "ALLOWED_BG") {
624 _D("[__SUSPEND__] allowed background");
625 impl_->allowed_bg_ = true;
626 RemoveSuspendTimer();
630 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
631 if (impl_->core_delegator_)
632 impl_->core_delegator_->OnControl(std::move(b));
634 OnControl(std::move(b));
635 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
638 _D("[APP %d] AUL event: AUL_RESUME", getpid());
639 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
640 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
641 if (bg == "ALLOWED_BG") {
642 _D("[__SUSPEND__] allowed background");
643 impl_->allowed_bg_ = true;
644 RemoveSuspendTimer();
649 _D("[APP %d] AUL event: AUL_TERMINATE", getpid());
650 aul_status_update(STATUS_DYING);
651 if (!impl_->allowed_bg_)
652 RemoveSuspendTimer();
656 case AUL_TERMINATE_INST:
657 case AUL_TERMINATE_BG_INST:
658 case AUL_TERMINATE_BGAPP:
659 _D("[APP %d] AUL event: %d", getpid(), type);
660 if (!impl_->allowed_bg_)
661 RemoveSuspendTimer();
664 _D("[APP %d] AUL event: AUL_WAKE", getpid());
665 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
666 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
667 RemoveSuspendTimer();
668 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
669 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
670 impl_->suspended_state_ = false;
675 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
676 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
677 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
678 RemoveSuspendTimer();
683 case AUL_UPDATE_REQUESTED:
684 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
685 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
688 _D("[APP %d] AUL event: %d", getpid(), type);
696 int AppCoreBase::OnCreate() {
697 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
698 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
699 if (base->impl_->core_delegator_) {
700 return base->impl_->core_delegator_->OnReceive(type,
701 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
703 return base->OnReceive(type,
704 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
706 if (ret < 0 && ret != AUL_R_ECANCELED) {
707 _E("aul_launch_init() is failed. error(%d)", ret);
711 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
713 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
720 int AppCoreBase::OnControl(tizen_base::Bundle b) {
724 int AppCoreBase::OnTerminate() {
729 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
730 impl_->core_delegator_ = delegator;
733 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
734 impl_->loop_delegator_ = delegator;
737 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
738 if (appid == nullptr)
741 /* com.vendor.name -> name */
742 const char* name_token = strrchr(appid, '.');
743 if (name_token == nullptr)
750 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
751 const char* res_path = aul_get_app_resource_path();
752 if (res_path == nullptr) {
753 _E("Failed to get resource path");
757 return std::string(res_path) + PATH_LOCALE;
760 int AppCoreBase::OnSetI18n() {
761 char appid[PATH_MAX];
762 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
764 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
768 std::string name = impl_->GetAppName(appid);
772 std::string locale_dir = impl_->GetLocaleResourceDir();
773 if (locale_dir.empty())
776 return SetI18n(move(name), move(locale_dir));
779 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
780 int val = vconf_keynode_get_int(key);
781 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
782 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
783 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
787 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
792 if (__rotation.ref == 0) {
794 if (feature_ & FEATURE_CHARGER_STATUS) {
795 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
796 ChargerStatusChangedCb);
801 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
802 if (__rotation.ref == 0) {
803 if (feature_ & FEATURE_CHARGER_STATUS) {
804 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
805 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
806 ChargerStatusChangedCb, parent_);
807 if (__rotation.charger_status)
817 int AppCoreBase::OnSetEvent(IEvent::Type event) {
819 case IEvent::Type::LOW_BATTERY:
820 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
821 impl_->OnLowBatteryCb, this);
823 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
824 impl_->RegisterRotationChangedEvent();
826 case IEvent::Type::SUSPENDED_STATE_CHANGE:
835 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
837 case IEvent::Type::LOW_BATTERY:
838 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
839 impl_->OnLowBatteryCb);
841 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
842 impl_->UnregisterRotationChangedEvent();
844 case IEvent::Type::SUSPENDED_STATE_CHANGE:
853 int AppCoreBase::OnTrimMemory() {
854 int (*sqlite3_free_heap_memory)(int);
856 sqlite3_free_heap_memory = reinterpret_cast<
857 decltype(sqlite3_free_heap_memory)>(
858 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
859 if (sqlite3_free_heap_memory)
860 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
866 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
868 for (auto& ev : impl_->events_) {
869 if (ev->GetType() == event->GetType()) {
876 if (impl_->core_delegator_)
877 impl_->core_delegator_->OnSetEvent(event->GetType());
879 OnSetEvent(event->GetType());
882 impl_->events_.push_back(move(event));
885 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
887 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
888 if (event.get() == ptr.get()) {
898 void AppCoreBase::FlushMemory() {
899 if (impl_->core_delegator_)
900 impl_->core_delegator_->OnTrimMemory();
905 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
906 _D("[__SUSPEND__] flush case");
907 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
908 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
909 impl_->suspended_state_ = true;
913 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
915 throw std::runtime_error("invalid rotation state");
917 return __rotation.rm;
920 bool AppCoreBase::IsBgAllowed() {
921 return impl_->allowed_bg_;
924 bool AppCoreBase::IsSuspended() {
925 return impl_->suspended_state_;
928 void AppCoreBase::ToggleSuspendedState() {
929 impl_->suspended_state_ = !impl_->suspended_state_;
932 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
933 const std::string& lang) {
934 std::istringstream ss(lang);
935 std::list<std::string> li;
938 while (std::getline(ss, token, ':'))
944 void AppCoreBase::Impl::AppendDefaultLangs(std::vector<std::string>& langs) {
945 langs.push_back("en_US");
946 langs.push_back("en_GB");
947 langs.push_back("en");
950 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
952 if (cstr == nullptr || delim == nullptr)
955 auto str = std::string(cstr);
956 auto idx = str.find(delim);
957 return str.substr(0, idx);
960 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
961 if (locale_dir_.empty())
964 DIR* dp = opendir(locale_dir_.c_str());
968 std::map<std::string, std::set<std::string>> table;
969 struct dirent *dentry;
970 while ((dentry = readdir(dp)) != nullptr) {
971 if (!strcmp(dentry->d_name, ".") ||
972 !strcmp(dentry->d_name, ".."))
975 std::string buf = locale_dir_ + "/" + dentry->d_name;
976 struct stat stat_buf;
977 int ret = stat(buf.c_str(), &stat_buf);
978 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
981 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
982 if (parent_lang.empty()) {
987 table[parent_lang].insert(dentry->d_name);
994 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
995 std::vector<std::string>& langs,
996 std::map<std::string, std::set<std::string>>& table) {
1000 langs.push_back(lang);
1001 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
1002 if (extract_lang.empty())
1005 if (std::find(langs.begin(), langs.end(), extract_lang) != langs.end())
1008 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
1009 if (parent_lang.empty())
1012 if (table.find(parent_lang) == table.end())
1015 auto it = table[parent_lang].find(extract_lang);
1016 if (it != table[parent_lang].end()) {
1017 std::string value = *it;
1018 if (std::find(langs.begin(), langs.end(), value) == langs.end())
1019 langs.push_back(std::move(value));
1021 table[parent_lang].erase(it);
1025 it = table[parent_lang].find(parent_lang);
1026 if (it != table[parent_lang].end()) {
1027 std::string value = *it;
1028 if (std::find(langs.begin(), langs.end(), value) == langs.end())
1029 langs.push_back(std::move(value));
1031 table[parent_lang].erase(parent_lang);
1035 if (!table[parent_lang].empty()) {
1036 auto i = table[parent_lang].begin();
1037 std::string value = *i;
1038 if (std::find(langs.begin(), langs.end(), value) == langs.end())
1039 langs.push_back(std::move(value));
1041 table[parent_lang].erase(i);
1045 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
1046 std::list<std::string> l = SplitLanguage(lang);
1050 auto table = GetLangTable();
1054 std::vector<std::string> langs;
1056 AppendLangs(i, langs, table);
1058 AppendDefaultLangs(langs);
1060 for (auto& i : langs) {
1070 void AppCoreBase::Impl::UpdateLang() {
1071 char* lang = vconf_get_str(VCONFKEY_LANGSET);
1072 if (lang == nullptr)
1075 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1076 std::string language = GetLanguage(lang);
1077 if (!language.empty()) {
1078 _D("*****language(%s)", language.c_str());
1079 setenv("LANGUAGE", language.c_str(), 1);
1081 setenv("LANGUAGE", lang, 1);
1083 setenv("LANG", lang, 1);
1084 setenv("LC_MESSAGES", lang, 1);
1085 setenv("LC_ALL", lang, 1);
1086 char* r = setlocale(LC_ALL, "");
1088 r = setlocale(LC_ALL, "en_US.UTF-8");
1090 _D("*****appcore setlocale=%s\n", r);
1092 _D("*****appcore setlocale=\"C\"");
1093 setenv("LC_ALL", "C", 1);
1094 r = setlocale(LC_ALL, "");
1096 _E("failed to setlocale");
1101 void AppCoreBase::Impl::UpdateRegion() {
1102 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1103 if (region == nullptr)
1106 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1107 setenv("LC_CTYPE", region, 1);
1108 setenv("LC_NUMERIC", region, 1);
1109 setenv("LC_TIME", region, 1);
1110 setenv("LC_COLLATE", region, 1);
1111 setenv("LC_MONETARY", region, 1);
1112 setenv("LC_PAPER", region, 1);
1113 setenv("LC_NAME", region, 1);
1114 setenv("LC_ADDRESS", region, 1);
1115 setenv("LC_TELEPHONE", region, 1);
1116 setenv("LC_MEASUREMENT", region, 1);
1117 setenv("LC_IDENTIFICATION", region, 1);
1118 char* r = setlocale(LC_ALL, "");
1120 _D("*****appcore setlocale=%s\n", r);
1122 _D("*****appcore setlocale=\"C\"");
1123 setenv("LC_ALL", "C", 1);
1124 r = setlocale(LC_ALL, "");
1126 _E("failed to setlocale");
1130 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1131 if (domain_name.empty()) {
1136 if (!dir_name.empty())
1137 impl_->locale_dir_ = dir_name;
1139 impl_->UpdateLang();
1140 impl_->UpdateRegion();
1142 char* r = setlocale(LC_ALL, "");
1143 /* if locale is not set properly, try to set "en_US" again */
1145 r = setlocale(LC_ALL, "en_US.UTF-8");
1147 _E("appcore: setlocale() error");
1148 _D("*****appcore setlocale=\"C\"");
1149 setenv("LC_ALL", "C", 1);
1150 r = setlocale(LC_ALL, "");
1152 _E("failed to setlocale");
1157 _D("*****appcore setlocale=%s\n", r);
1159 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1161 _E("appcore: bindtextdomain() error");
1163 r = textdomain(domain_name.c_str());
1165 _E("appcore: textdomain() error");
1170 void AppCoreBase::Exit() {
1171 aul_status_update(STATUS_DYING);
1172 if (impl_->loop_delegator_)
1173 impl_->loop_delegator_->OnLoopExit();
1178 void AppCoreBase::AddSuspendTimer() {
1179 impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1180 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1181 base->FlushMemory();
1186 void AppCoreBase::RemoveSuspendTimer() {
1187 if (impl_->tid_ > 0) {
1188 GLib::SourceRemove(impl_->tid_);
1193 void AppCoreBase::SetDisplayState(DisplayState state) {
1194 __display_state = state;
1197 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1198 return __display_state;
1201 int AppCoreBase::EnableWatchdog() {
1202 _I("[__APPCORE_WATCHDOG__] enable");
1203 return aul_watchdog_enable();
1206 int AppCoreBase::DisableWatchdog() {
1207 _I("[__APPCORE_WATCHDOG__] disable");
1208 return aul_watchdog_disable();
1211 int AppCoreBase::KickWatchdog() {
1212 _I("[__APPCORE_WATCHDOG__] kick");
1213 return aul_watchdog_kick();
1216 void AppCoreBase::Run(int argc, char** argv) {
1221 void AppCoreBase::Init(int argc, char** argv) {
1223 impl_->suspended_state_ = false;
1224 impl_->allowed_bg_ = false;
1225 impl_->argc_ = argc;
1226 impl_->argv_ = argv;
1227 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1228 if (impl_->loop_delegator_)
1229 impl_->loop_delegator_->OnLoopInit(argc, argv);
1231 OnLoopInit(argc, argv);
1233 signal(SIGTERM, [](int n) {
1234 _W("sigterm handler");
1235 if (context_ != nullptr)
1239 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1241 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1242 GLib::IdleAdd(Impl::InitSuspendCb, this);
1244 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1245 if (!impl_->dirty_) {
1246 impl_->dirty_ = true;
1248 for (auto& e : impl_->events_) {
1249 if (impl_->core_delegator_)
1250 impl_->core_delegator_->OnSetEvent(e->GetType());
1252 OnSetEvent(e->GetType());
1255 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1257 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1258 impl_->VerifyLanguage();
1259 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1261 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1262 impl_->SetDefaultEvents();
1263 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1265 if (impl_->core_delegator_)
1266 impl_->core_delegator_->OnSetI18n();
1270 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1272 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1274 if (impl_->core_delegator_)
1275 create = impl_->core_delegator_->OnCreate();
1277 create = OnCreate();
1278 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1280 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1284 if (impl_->loop_delegator_)
1285 impl_->loop_delegator_->OnLoopRun();
1290 void AppCoreBase::Fini() {
1294 void AppCoreBase::Dispose() {
1295 aul_status_update(STATUS_DYING);
1297 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1299 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1300 if (impl_->core_delegator_)
1301 impl_->core_delegator_->OnTerminate();
1304 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1306 for (auto& e : impl_->events_) {
1307 if (impl_->core_delegator_)
1308 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1310 OnUnsetEvent(e->GetType());
1313 impl_->UnsetDefaultEvents();
1315 GLib::SourceRemove(impl_->sid_);
1319 RemoveSuspendTimer();
1320 impl_->dirty_ = false;
1321 if (impl_->loop_delegator_)
1322 impl_->loop_delegator_->OnLoopFinish();
1327 void AppCoreBase::SetFeature(int feature) {
1328 impl_->feature_ = feature;
1331 int AppCoreBase::GetFeature() const {
1332 return impl_->feature_;
1335 } // namespace tizen_cpp