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.
17 #include "app-core-cpp/app_core_base.hh"
20 #include <aul_app_lifecycle.h>
21 #include <aul_watchdog.h>
22 #include <bundle_internal.h>
26 #include <glib-unix.h>
29 #include <linux/limits.h>
32 #include <sensor_internal.h>
37 #include <sys/types.h>
38 #include <system_info.h>
53 #include "app-core-cpp/app_core_plugin_private.hh"
54 #include "app-core-cpp/exit_handler_private.hh"
55 #include "app-core-cpp/sigterm_handler_private.hh"
56 #include "common/glib_private.hh"
57 #include "common/log_private.hh"
59 extern "C" void aul_finalize();
62 AppCoreBase* AppCoreBase::context_ = nullptr;
66 internal::ExitHandler exit_handler;
67 internal::SigtermHandler sigterm_handler;
78 TizenProfile TizenProfileGet() {
79 static TizenProfile profile = TizenProfile::Unknown;
80 if (__builtin_expect(profile != TizenProfile::Unknown, 1))
83 char* profile_name = nullptr;
84 system_info_get_platform_string("http://tizen.org/feature/profile",
86 if (profile_name == nullptr)
89 switch (*profile_name) {
92 profile = TizenProfile::Mobile;
96 profile = TizenProfile::Wearable;
100 profile = TizenProfile::Tv;
104 profile = TizenProfile::Ivi;
107 profile = TizenProfile::Common;
115 constexpr const char PATH_LOCALE[] = "locale";
116 constexpr int SQLITE_FLUSH_MAX = 1024 * 1024;
117 constexpr const char RESOURCED_FREEZER_PATH[] =
118 "/Org/Tizen/ResourceD/Freezer";
119 constexpr const char RESOURCED_FREEZER_INTERFACE[] =
120 "org.tizen.resourced.freezer";
121 constexpr const char RESOURCED_FREEZER_SIGNAL[] =
128 tizen_cpp::AppCoreBase::RotationState rm;
134 GDBusConnection* __bus;
135 guint __suspend_dbus_handler_initialized;
136 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
140 class AppCoreBase::EventBase::Impl {
142 friend class AppCoreBase;
143 Type type_ = IEvent::Type::START;
144 std::string str_val_;
148 class AppCoreBase::Impl {
150 explicit Impl(AppCoreBase* parent) : parent_(parent) {
151 if (TizenProfileGet() & TizenProfile::Wearable)
152 feature_ |= FEATURE_CHARGER_STATUS;
153 if (!(TizenProfileGet() & TizenProfile::Tv))
154 feature_ |= FEATURE_BACKGROUND_MANAGEMENT;
158 void UnregisterRotationChangedEvent();
159 void RegisterRotationChangedEvent();
160 std::string GetAppName(const char* appid);
161 std::string GetLocaleResourceDir();
164 std::list<std::string> SplitLanguage(const std::string& lang);
165 std::string GetLanguage(std::string lang);
166 void AppendDefaultLangs(std::vector<std::string>& lang_set);
167 std::string GetStringBefore(const char* str, const char* delim);
168 std::map<std::string, std::set<std::string>> GetLangTable();
169 void AppendLangs(const std::string& lang, std::vector<std::string>& lang_set,
170 std::map<std::string, std::set<std::string>>& table);
172 void OnFreezerSignal();
175 void InvokeCallback(T event, IEvent::Type type) {
176 for (auto& i : events_) {
177 if (i->GetType() != type)
180 if (i->GetVal(event) != event ||
181 type == IEvent::Type::START ||
182 type == IEvent::Type::UPDATE_REQUESTED) {
189 static void InitSuspendDbusHandler(gpointer data);
190 static gboolean InitSuspendCb(gpointer data);
191 static gboolean InvokeLangChangeCb(gpointer data);
192 static void ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
193 const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
194 static void OnLowBatteryCb(keynode_t* key, void* data);
195 static void LockCb(keynode_t* node, void* user_data);
196 static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
197 sensor_data_t* data, void* user_data);
198 static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
199 static void LanguageChangeCb(keynode_t* key, void* data);
200 static void RegionChangeCb(keynode_t* key, void* data);
201 static void LowMemoryCb(keynode_t* key, void* data);
204 RotationState GetRm(sensor_data_t data);
205 void VerifyLanguage();
206 void SetDefaultEvents();
207 void UnsetDefaultEvents();
208 void PluginInit(int argc, char** argv);
212 friend class AppCoreBase;
213 AppCoreBase* parent_ = nullptr;
216 char** argv_ = nullptr;
217 bool suspended_state_ = false;
218 bool allowed_bg_ = false;
220 unsigned int tid_ = 0;
221 std::list<std::shared_ptr<EventBase>> events_;
222 std::string locale_dir_;
225 IAppCore* core_delegator_ = nullptr;
226 IMainLoop* loop_delegator_ = nullptr;
227 guint signal_handler_source_ = 0;
228 std::unique_ptr<AppCorePlugin> plugin_;
231 AppCoreBase::EventBase::EventBase(Type type)
232 : impl_(std::make_unique<EventBase::Impl>()) {
236 AppCoreBase::EventBase::~EventBase() = default;
238 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
242 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
243 return impl_->str_val_;
246 int AppCoreBase::EventBase::GetVal(int cur) const {
250 void AppCoreBase::EventBase::SetVal(std::string val) {
251 impl_->str_val_ = std::move(val);
254 void AppCoreBase::EventBase::SetVal(int val) {
255 impl_->val_ = std::move(val);
258 AppCoreBase::AppCoreBase()
259 : impl_(std::make_unique<AppCoreBase::Impl>(this)) {
260 if (context_ != nullptr) {
261 _E("Context is already initialized");
267 AppCoreBase::~AppCoreBase() {
272 AppCoreBase* AppCoreBase::GetContext() {
273 if (context_ == nullptr) {
274 _E("Context is not initialized.");
281 void AppCoreBase::Impl::ChangeLang() {
282 const char* lang = getenv("LANG");
286 InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
289 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
290 impl_->InvokeCallback(event, type);
293 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
294 impl_->InvokeCallback(event, type);
297 void AppCoreBase::Impl::OnFreezerSignal() {
298 if (!allowed_bg_ && suspended_state_) {
299 parent_->RemoveSuspendTimer();
300 InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
301 IEvent::Type::SUSPENDED_STATE_CHANGE);
302 suspended_state_ = false;
303 parent_->AddSuspendTimer();
307 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
308 if (data.value_count <= 0) {
309 _E("Failed to get sensor data");
310 return ROTATION_UNKNOWN;
313 int event = data.values[0];
315 case AUTO_ROTATION_DEGREE_0:
316 return ROTATION_PORTRAIT_NORMAL;
317 case AUTO_ROTATION_DEGREE_90:
318 return ROTATION_LANDSCAPE_NORMAL;
319 case AUTO_ROTATION_DEGREE_180:
320 return ROTATION_PORTRAIT_REVERSE;
321 case AUTO_ROTATION_DEGREE_270:
322 return ROTATION_LANDSCAPE_REVERSE;
324 return ROTATION_UNKNOWN;
328 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
329 if (__suspend_dbus_handler_initialized)
332 if (__bus == nullptr) {
333 GError* err = nullptr;
334 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
335 if (__bus == nullptr) {
336 _E("Failed to connect to the D-BUS daemon: %s", err ? err->message : "");
344 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
345 __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
346 RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
347 ReceiveSuspendSignalCb, data, nullptr);
349 if (__suspend_dbus_handler_initialized == 0) {
350 _E("g_dbus_connection_signal_subscribe() is failed.");
354 _D("[__SUSPEND__] suspend signal initialized");
357 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
358 InitSuspendDbusHandler(data);
359 return G_SOURCE_REMOVE;
362 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
363 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
364 base->impl_->sid_ = 0;
365 base->impl_->ChangeLang();
366 return G_SOURCE_REMOVE;
369 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
370 const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
371 gpointer user_data) {
372 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
375 g_variant_get(parameters, "(ii)", &status, &pid);
376 if (pid == getpid() && status == 0) {
377 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
378 base->impl_->OnFreezerSignal();
383 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
384 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
385 if (base->impl_->sid_) {
386 GLib::SourceRemove(base->impl_->sid_);
387 base->impl_->sid_ = 0;
390 char* val = vconf_keynode_get_str(key);
394 base->impl_->UpdateLang();
395 base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
398 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
399 const char* name = vconf_keynode_get_name(key);
403 if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
404 strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
407 char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
410 std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
412 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
413 base->impl_->UpdateRegion();
414 base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
417 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
418 int val = vconf_keynode_get_int(key);
419 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
420 base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
421 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
425 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
427 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
428 if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
429 __rotation.charger_status = vconf_keynode_get_int(keynode);
430 if (__rotation.ref) {
431 if (__rotation.charger_status) {
432 base->impl_->InitRotation();
434 base->impl_->FiniRotation();
438 _D("charger status(%d)", __rotation.charger_status);
442 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
443 AppCoreBase::RotationState rm;
444 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
446 __rotation.lock = !vconf_keynode_get_bool(node);
447 if (__rotation.lock) {
448 _D("Rotation locked");
449 rm = ROTATION_PORTRAIT_NORMAL;
451 _D("Rotation unlocked");
453 bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
455 _E("Failed to get sensor data");
459 rm = base->impl_->GetRm(data);
460 if (rm == ROTATION_UNKNOWN) {
466 if (__rotation.rm == rm)
469 _D("Rotation: %d -> %d", __rotation.rm, rm);
471 base->impl_->InvokeCallback(__rotation.rm,
472 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
475 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
476 unsigned int event_type, sensor_data_t* data, void* user_data) {
483 if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
486 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
487 AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
488 if (rm == ROTATION_UNKNOWN) {
493 _D("Rotation: %d -> %d", __rotation.rm, rm);
495 base->impl_->InvokeCallback(__rotation.rm,
496 IEvent::Type::DEVICE_ORIENTATION_CHANGED);
499 void AppCoreBase::Impl::InitRotation() {
500 if (__rotation.initialized)
503 sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
504 __rotation.conn = sensord_connect(sensor);
505 if (__rotation.conn < 0) {
506 _E("Failed to connect sensord");
510 bool r = sensord_register_event(__rotation.conn,
511 AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
512 AutoRotationChangedCb, parent_);
514 _E("Failed to register auto rotation change event");
515 sensord_disconnect(__rotation.conn);
519 r = sensord_start(__rotation.conn, 0);
521 _E("Failed to start sensord");
522 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
523 sensord_disconnect(__rotation.conn);
528 vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
529 vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
532 __rotation.lock = !lock;
533 __rotation.initialized = true;
536 void AppCoreBase::Impl::FiniRotation() {
537 if (!__rotation.initialized)
540 vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
541 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
542 sensord_stop(__rotation.conn);
543 sensord_disconnect(__rotation.conn);
546 __rotation.initialized = false;
549 void AppCoreBase::Impl::VerifyLanguage() {
550 const char* env_lang = getenv("LANG");
551 if (env_lang == nullptr)
554 char* lang = vconf_get_str(VCONFKEY_LANGSET);
558 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
560 if (strcmp(env_lang, lang) != 0) {
561 _I("LANG(%s), LANGSET(%s)", env_lang, lang);
562 sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
566 void AppCoreBase::Impl::SetDefaultEvents() {
567 vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
568 int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
571 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
575 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
578 void AppCoreBase::Impl::UnsetDefaultEvents() {
579 vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
580 int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
582 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
584 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
587 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
590 _D("[APP %d] AUL event: AUL_START", getpid());
591 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
592 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
593 if (bg == "ALLOWED_BG") {
594 _D("[__SUSPEND__] allowed background");
595 impl_->allowed_bg_ = true;
596 RemoveSuspendTimer();
600 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
601 if (impl_->core_delegator_)
602 impl_->core_delegator_->OnControl(std::move(b));
604 OnControl(std::move(b));
605 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
608 _D("[APP %d] AUL event: AUL_RESUME", getpid());
609 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
610 std::string bg = b.GetString(AUL_K_ALLOWED_BG);
611 if (bg == "ALLOWED_BG") {
612 _D("[__SUSPEND__] allowed background");
613 impl_->allowed_bg_ = true;
614 RemoveSuspendTimer();
619 _D("[APP %d] AUL event: AUL_TERMINATE", getpid());
620 aul_status_update(STATUS_DYING);
621 if (!impl_->allowed_bg_)
622 RemoveSuspendTimer();
626 case AUL_TERMINATE_INST:
627 case AUL_TERMINATE_BG_INST:
628 case AUL_TERMINATE_BGAPP:
629 _D("[APP %d] AUL event: %d", getpid(), type);
630 if (!impl_->allowed_bg_)
631 RemoveSuspendTimer();
634 _D("[APP %d] AUL event: AUL_WAKE", getpid());
635 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
636 if (!impl_->allowed_bg_ && impl_->suspended_state_) {
637 RemoveSuspendTimer();
638 int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
639 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
640 impl_->suspended_state_ = false;
645 _D("[APP %d] AUL event: AUL_SUSPEND", getpid());
646 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
647 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
648 RemoveSuspendTimer();
653 case AUL_UPDATE_REQUESTED:
654 _D("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
655 impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
658 _D("[APP %d] AUL event: %d", getpid(), type);
666 int AppCoreBase::OnCreate() {
667 int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
668 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
669 if (base->impl_->core_delegator_) {
670 return base->impl_->core_delegator_->OnReceive(type,
671 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
673 return base->OnReceive(type,
674 b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
676 if (ret < 0 && ret != AUL_R_ECANCELED) {
677 _E("aul_launch_init() is failed. error(%d)", ret);
681 ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
683 _E("aul_launch_argv_handler() is failed. error(%d)", ret);
690 int AppCoreBase::OnControl(tizen_base::Bundle b) {
694 int AppCoreBase::OnTerminate() {
699 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
700 impl_->core_delegator_ = delegator;
703 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
704 impl_->loop_delegator_ = delegator;
707 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
708 if (appid == nullptr)
711 /* com.vendor.name -> name */
712 const char* name_token = strrchr(appid, '.');
713 if (name_token == nullptr)
720 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
721 const char* res_path = aul_get_app_resource_path();
722 if (res_path == nullptr) {
723 _E("Failed to get resource path");
727 return std::string(res_path) + PATH_LOCALE;
730 int AppCoreBase::OnSetI18n() {
731 char appid[PATH_MAX];
732 int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
734 _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
738 std::string name = impl_->GetAppName(appid);
742 std::string locale_dir = impl_->GetLocaleResourceDir();
743 if (locale_dir.empty())
746 return SetI18n(move(name), move(locale_dir));
749 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
750 int val = vconf_keynode_get_int(key);
751 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
752 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
753 base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
757 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
762 if (__rotation.ref == 0) {
764 if (feature_ & FEATURE_CHARGER_STATUS) {
765 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
766 ChargerStatusChangedCb);
771 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
772 if (__rotation.ref == 0) {
773 if (feature_ & FEATURE_CHARGER_STATUS) {
774 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
775 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
776 ChargerStatusChangedCb, parent_);
777 if (__rotation.charger_status)
787 int AppCoreBase::OnSetEvent(IEvent::Type event) {
789 case IEvent::Type::LOW_BATTERY:
790 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
791 impl_->OnLowBatteryCb, this);
793 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
794 impl_->RegisterRotationChangedEvent();
796 case IEvent::Type::SUSPENDED_STATE_CHANGE:
805 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
807 case IEvent::Type::LOW_BATTERY:
808 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
809 impl_->OnLowBatteryCb);
811 case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
812 impl_->UnregisterRotationChangedEvent();
814 case IEvent::Type::SUSPENDED_STATE_CHANGE:
823 int AppCoreBase::OnTrimMemory() {
824 int (*sqlite3_free_heap_memory)(int);
826 sqlite3_free_heap_memory = reinterpret_cast<
827 decltype(sqlite3_free_heap_memory)>(
828 dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
829 if (sqlite3_free_heap_memory)
830 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
836 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
838 for (auto& ev : impl_->events_) {
839 if (ev->GetType() == event->GetType()) {
846 if (impl_->core_delegator_)
847 impl_->core_delegator_->OnSetEvent(event->GetType());
849 OnSetEvent(event->GetType());
852 impl_->events_.push_back(move(event));
855 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
857 impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
858 if (event.get() == ptr.get()) {
868 void AppCoreBase::FlushMemory() {
869 if (impl_->core_delegator_)
870 impl_->core_delegator_->OnTrimMemory();
875 if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
876 _D("[__SUSPEND__] flush case");
877 int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
878 impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
879 impl_->suspended_state_ = true;
883 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
885 throw std::runtime_error("invalid rotation state");
887 return __rotation.rm;
890 bool AppCoreBase::IsBgAllowed() {
891 return impl_->allowed_bg_;
894 bool AppCoreBase::IsSuspended() {
895 return impl_->suspended_state_;
898 void AppCoreBase::ToggleSuspendedState() {
899 impl_->suspended_state_ = !impl_->suspended_state_;
902 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
903 const std::string& lang) {
904 std::istringstream ss(lang);
905 std::list<std::string> li;
908 while (std::getline(ss, token, ':'))
914 void AppCoreBase::Impl::AppendDefaultLangs(std::vector<std::string>& langs) {
915 langs.push_back("en_US");
916 langs.push_back("en_GB");
917 langs.push_back("en");
920 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
922 if (cstr == nullptr || delim == nullptr)
925 auto str = std::string(cstr);
926 auto idx = str.find(delim);
927 return str.substr(0, idx);
930 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
931 if (locale_dir_.empty())
934 DIR* dp = opendir(locale_dir_.c_str());
938 std::map<std::string, std::set<std::string>> table;
939 struct dirent *dentry;
940 while ((dentry = readdir(dp)) != nullptr) {
941 if (!strcmp(dentry->d_name, ".") ||
942 !strcmp(dentry->d_name, ".."))
945 std::string buf = locale_dir_ + "/" + dentry->d_name;
946 struct stat stat_buf;
947 int ret = stat(buf.c_str(), &stat_buf);
948 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
951 std::string parent_lang = GetStringBefore(dentry->d_name, "_");
952 if (parent_lang.empty()) {
957 table[parent_lang].insert(dentry->d_name);
964 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
965 std::vector<std::string>& langs,
966 std::map<std::string, std::set<std::string>>& table) {
970 langs.push_back(lang);
971 std::string extract_lang = GetStringBefore(lang.c_str(), ".");
972 if (extract_lang.empty())
975 if (std::find(langs.begin(), langs.end(), extract_lang) != langs.end())
978 std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
979 if (parent_lang.empty())
982 if (table.find(parent_lang) == table.end())
985 auto it = table[parent_lang].find(extract_lang);
986 if (it != table[parent_lang].end()) {
987 std::string value = *it;
988 if (std::find(langs.begin(), langs.end(), value) == langs.end())
989 langs.push_back(std::move(value));
991 table[parent_lang].erase(it);
995 it = table[parent_lang].find(parent_lang);
996 if (it != table[parent_lang].end()) {
997 std::string value = *it;
998 if (std::find(langs.begin(), langs.end(), value) == langs.end())
999 langs.push_back(std::move(value));
1001 table[parent_lang].erase(parent_lang);
1005 if (!table[parent_lang].empty()) {
1006 auto i = table[parent_lang].begin();
1007 std::string value = *i;
1008 if (std::find(langs.begin(), langs.end(), value) == langs.end())
1009 langs.push_back(std::move(value));
1011 table[parent_lang].erase(i);
1015 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
1016 std::list<std::string> l = SplitLanguage(lang);
1020 auto table = GetLangTable();
1024 std::vector<std::string> langs;
1026 AppendLangs(i, langs, table);
1028 AppendDefaultLangs(langs);
1030 for (auto& i : langs) {
1040 void AppCoreBase::Impl::UpdateLang() {
1041 char* lang = vconf_get_str(VCONFKEY_LANGSET);
1042 if (lang == nullptr)
1045 std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1046 std::string language = GetLanguage(lang);
1047 if (!language.empty()) {
1048 _D("*****language(%s)", language.c_str());
1049 setenv("LANGUAGE", language.c_str(), 1);
1051 setenv("LANGUAGE", lang, 1);
1053 setenv("LANG", lang, 1);
1054 setenv("LC_MESSAGES", lang, 1);
1055 setenv("LC_ALL", lang, 1);
1056 char* r = setlocale(LC_ALL, "");
1058 r = setlocale(LC_ALL, "en_US.UTF-8");
1060 _D("*****appcore setlocale=%s\n", r);
1062 _D("*****appcore setlocale=\"C\"");
1063 setenv("LC_ALL", "C", 1);
1064 r = setlocale(LC_ALL, "");
1066 _E("failed to setlocale");
1071 void AppCoreBase::Impl::UpdateRegion() {
1072 char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1073 if (region == nullptr)
1076 std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1077 setenv("LC_CTYPE", region, 1);
1078 setenv("LC_NUMERIC", region, 1);
1079 setenv("LC_TIME", region, 1);
1080 setenv("LC_COLLATE", region, 1);
1081 setenv("LC_MONETARY", region, 1);
1082 setenv("LC_PAPER", region, 1);
1083 setenv("LC_NAME", region, 1);
1084 setenv("LC_ADDRESS", region, 1);
1085 setenv("LC_TELEPHONE", region, 1);
1086 setenv("LC_MEASUREMENT", region, 1);
1087 setenv("LC_IDENTIFICATION", region, 1);
1088 char* r = setlocale(LC_ALL, "");
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");
1100 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1101 if (domain_name.empty()) {
1106 if (!dir_name.empty())
1107 impl_->locale_dir_ = dir_name;
1109 impl_->UpdateLang();
1110 impl_->UpdateRegion();
1112 char* r = setlocale(LC_ALL, "");
1113 /* if locale is not set properly, try to set "en_US" again */
1115 r = setlocale(LC_ALL, "en_US.UTF-8");
1117 _E("appcore: setlocale() error");
1118 _D("*****appcore setlocale=\"C\"");
1119 setenv("LC_ALL", "C", 1);
1120 r = setlocale(LC_ALL, "");
1122 _E("failed to setlocale");
1127 _D("*****appcore setlocale=%s\n", r);
1129 r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1131 _E("appcore: bindtextdomain() error");
1133 r = textdomain(domain_name.c_str());
1135 _E("appcore: textdomain() error");
1140 void AppCoreBase::Exit() {
1141 aul_status_update(STATUS_DYING);
1142 if (impl_->loop_delegator_)
1143 impl_->loop_delegator_->OnLoopExit();
1148 void AppCoreBase::AddSuspendTimer() {
1149 impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1150 AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1151 base->FlushMemory();
1156 void AppCoreBase::RemoveSuspendTimer() {
1157 if (impl_->tid_ > 0) {
1158 GLib::SourceRemove(impl_->tid_);
1163 void AppCoreBase::SetDisplayState(DisplayState state) {
1164 __display_state = state;
1167 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1168 return __display_state;
1171 int AppCoreBase::EnableWatchdog() {
1172 _I("[__APPCORE_WATCHDOG__] enable");
1173 return aul_watchdog_enable();
1176 int AppCoreBase::DisableWatchdog() {
1177 _I("[__APPCORE_WATCHDOG__] disable");
1178 return aul_watchdog_disable();
1181 int AppCoreBase::KickWatchdog() {
1182 _I("[__APPCORE_WATCHDOG__] kick");
1183 return aul_watchdog_kick();
1186 void AppCoreBase::Run(int argc, char** argv) {
1191 void AppCoreBase::Init(int argc, char** argv) {
1193 impl_->suspended_state_ = false;
1194 impl_->allowed_bg_ = false;
1195 impl_->argc_ = argc;
1196 impl_->argv_ = argv;
1197 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1198 sigterm_handler.Restore();
1199 if (impl_->loop_delegator_)
1200 impl_->loop_delegator_->OnLoopInit(argc, argv);
1202 OnLoopInit(argc, argv);
1204 impl_->signal_handler_source_ = g_unix_signal_add(SIGTERM,
1205 [](gpointer data) -> gboolean {
1206 _W("sigterm handler");
1207 if (context_ != nullptr) {
1209 context_->impl_->signal_handler_source_ = 0;
1212 return G_SOURCE_REMOVE;
1215 if (impl_->signal_handler_source_ == 0)
1216 _E("Failed to add sigterm handler.");
1218 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1220 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:PLUGIN_INIT");
1221 impl_->PluginInit(argc, argv);
1222 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1224 if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1225 GLib::IdleAdd(Impl::InitSuspendCb, this);
1227 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1228 if (!impl_->dirty_) {
1229 impl_->dirty_ = true;
1231 for (auto& e : impl_->events_) {
1232 if (impl_->core_delegator_)
1233 impl_->core_delegator_->OnSetEvent(e->GetType());
1235 OnSetEvent(e->GetType());
1238 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1240 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1241 impl_->VerifyLanguage();
1242 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1244 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1245 impl_->SetDefaultEvents();
1246 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1248 if (impl_->core_delegator_)
1249 impl_->core_delegator_->OnSetI18n();
1253 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1255 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1257 if (impl_->core_delegator_)
1258 create = impl_->core_delegator_->OnCreate();
1260 create = OnCreate();
1261 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1263 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1267 if (impl_->loop_delegator_)
1268 impl_->loop_delegator_->OnLoopRun();
1273 void AppCoreBase::Fini() {
1274 if (impl_->signal_handler_source_) {
1275 g_source_remove(impl_->signal_handler_source_);
1276 impl_->signal_handler_source_ = 0;
1282 void AppCoreBase::Dispose() {
1283 aul_status_update(STATUS_DYING);
1285 aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1287 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1288 if (impl_->core_delegator_)
1289 impl_->core_delegator_->OnTerminate();
1292 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1294 for (auto& e : impl_->events_) {
1295 if (impl_->core_delegator_)
1296 impl_->core_delegator_->OnUnsetEvent(e->GetType());
1298 OnUnsetEvent(e->GetType());
1301 impl_->UnsetDefaultEvents();
1303 GLib::SourceRemove(impl_->sid_);
1307 RemoveSuspendTimer();
1308 impl_->PluginFini();
1309 impl_->dirty_ = false;
1310 if (impl_->loop_delegator_)
1311 impl_->loop_delegator_->OnLoopFinish();
1316 void AppCoreBase::SetFeature(int feature) {
1317 impl_->feature_ = feature;
1320 int AppCoreBase::GetFeature() const {
1321 return impl_->feature_;
1324 void AppCoreBase::Impl::PluginInit(int argc, char** argv) {
1325 plugin_.reset(AppCorePlugin::Load());
1329 plugin_->Init(argc, argv);
1332 void AppCoreBase::Impl::PluginFini() {
1339 } // namespace tizen_cpp