Add new app event
[platform/core/appfw/app-core.git] / tizen-cpp / app-core-cpp / app_core_base.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "app-core-cpp/app_core_base.hh"
18
19 #include <aul.h>
20 #include <aul_app_lifecycle.h>
21 #include <aul_watchdog.h>
22 #include <bundle_internal.h>
23 #include <dlfcn.h>
24 #include <errno.h>
25 #include <gio/gio.h>
26 #include <glib-unix.h>
27 #include <glib.h>
28 #include <libintl.h>
29 #include <linux/limits.h>
30 #include <locale.h>
31 #include <malloc.h>
32 #include <sensor_internal.h>
33 #include <signal.h>
34 #include <stdbool.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <system_info.h>
39 #include <ttrace.h>
40 #include <unistd.h>
41 #include <vconf.h>
42
43 #include <algorithm>
44 #include <cstring>
45 #include <list>
46 #include <map>
47 #include <memory>
48 #include <set>
49 #include <sstream>
50 #include <utility>
51 #include <vector>
52
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"
58
59 extern "C" void aul_finalize();
60 namespace tizen_cpp {
61
62 AppCoreBase* AppCoreBase::context_ = nullptr;
63
64 namespace {
65
66 internal::ExitHandler exit_handler;
67 internal::SigtermHandler sigterm_handler;
68
69 enum TizenProfile {
70   Unknown = 0x00,
71   Mobile = 0x01,
72   Wearable = 0x02,
73   Tv = 0x04,
74   Ivi = 0x08,
75   Common = 0x10,
76 };
77
78 TizenProfile TizenProfileGet() {
79   static TizenProfile profile = TizenProfile::Unknown;
80   if (__builtin_expect(profile != TizenProfile::Unknown, 1))
81     return profile;
82
83   char* profile_name = nullptr;
84   system_info_get_platform_string("http://tizen.org/feature/profile",
85       &profile_name);
86   if (profile_name == nullptr)
87     return profile;
88
89   switch (*profile_name) {
90   case 'm':
91   case 'M':
92     profile = TizenProfile::Mobile;
93     break;
94   case 'w':
95   case 'W':
96     profile = TizenProfile::Wearable;
97     break;
98   case 't':
99   case 'T':
100     profile = TizenProfile::Tv;
101     break;
102   case 'i':
103   case 'I':
104     profile = TizenProfile::Ivi;
105     break;
106   default:
107     profile = TizenProfile::Common;
108     break;
109   }
110   free(profile_name);
111
112   return profile;
113 }
114
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[] =
122     "FreezerState";
123
124 struct Rotation {
125   int conn;
126   int lock;
127   int ref;
128   tizen_cpp::AppCoreBase::RotationState rm;
129   int charger_status;
130   bool initialized;
131 };
132
133 Rotation __rotation;
134 GDBusConnection* __bus;
135 guint __suspend_dbus_handler_initialized;
136 AppCoreBase::DisplayState __display_state = AppCoreBase::DISPLAY_STATE_UNKNOWN;
137
138 }  // namespace
139
140 class AppCoreBase::EventBase::Impl {
141  private:
142   friend class AppCoreBase;
143   Type type_ = IEvent::Type::START;
144   std::string str_val_;
145   int val_ = -1;
146 };
147
148 class AppCoreBase::Impl {
149  public:
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;
155   }
156
157  private:
158   void UnregisterRotationChangedEvent();
159   void RegisterRotationChangedEvent();
160   std::string GetAppName(const char* appid);
161   std::string GetLocaleResourceDir();
162   void UpdateLang();
163   void UpdateRegion();
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);
171   void ChangeLang();
172   void OnFreezerSignal();
173
174   template <class T>
175   void InvokeCallback(T event, IEvent::Type type) {
176     for (auto& i : events_) {
177       if (i->GetType() != type)
178         continue;
179
180       if (i->GetVal(event) != event ||
181           type == IEvent::Type::START ||
182           type == IEvent::Type::UPDATE_REQUESTED) {
183         i->SetVal(event);
184         i->OnEvent(event);
185       }
186     }
187   }
188
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 OnTimeZoneChangedCb(keynode_t* key, void* data);
196   static void LockCb(keynode_t* node, void* user_data);
197   static void AutoRotationChangedCb(sensor_t sensor, unsigned int event_type,
198       sensor_data_t* data, void* user_data);
199   static void ChargerStatusChangedCb(keynode_t* keynode, void* user_data);
200   static void LanguageChangeCb(keynode_t* key, void* data);
201   static void RegionChangeCb(keynode_t* key, void* data);
202   static void LowMemoryCb(keynode_t* key, void* data);
203   void InitRotation();
204   void FiniRotation();
205   RotationState GetRm(sensor_data_t data);
206   void VerifyLanguage();
207   void SetDefaultEvents();
208   void UnsetDefaultEvents();
209   void PluginInit(int argc, char** argv);
210   void PluginFini();
211
212  private:
213   friend class AppCoreBase;
214   AppCoreBase* parent_ = nullptr;
215
216   int argc_ = 0;
217   char** argv_ = nullptr;
218   bool suspended_state_ = false;
219   bool allowed_bg_ = false;
220   bool dirty_ = false;
221   unsigned int tid_ = 0;
222   std::list<std::shared_ptr<EventBase>> events_;
223   std::string locale_dir_;
224   guint sid_ = 0;
225   int feature_ = 0;
226   IAppCore* core_delegator_ = nullptr;
227   IMainLoop* loop_delegator_ = nullptr;
228   guint signal_handler_source_ = 0;
229   std::unique_ptr<AppCorePlugin> plugin_;
230 };
231
232 AppCoreBase::EventBase::EventBase(Type type)
233     : impl_(std::make_unique<EventBase::Impl>()) {
234   impl_->type_ = type;
235 }
236
237 AppCoreBase::EventBase::~EventBase() = default;
238
239 IAppCore::IEvent::Type AppCoreBase::EventBase::GetType() const {
240   return impl_->type_;
241 }
242
243 std::string AppCoreBase::EventBase::GetVal(std::string cur) const {
244   return impl_->str_val_;
245 }
246
247 int AppCoreBase::EventBase::GetVal(int cur) const {
248   return impl_->val_;
249 }
250
251 void AppCoreBase::EventBase::SetVal(std::string val) {
252   impl_->str_val_ = std::move(val);
253 }
254
255 void AppCoreBase::EventBase::SetVal(int val) {
256   impl_->val_ = std::move(val);
257 }
258
259 AppCoreBase::AppCoreBase()
260     : impl_(std::make_unique<AppCoreBase::Impl>(this)) {
261   if (context_ != nullptr) {
262     _E("Context is already initialized");
263   }
264
265   context_ = this;
266 }
267
268 AppCoreBase::~AppCoreBase() {
269   _I("");
270   context_ = nullptr;
271 }
272
273 AppCoreBase* AppCoreBase::GetContext() {
274   if (context_ == nullptr) {
275     _E("Context is not initialized.");
276     return nullptr;
277   }
278
279   return context_;
280 }
281
282 void AppCoreBase::Impl::ChangeLang() {
283   const char* lang = getenv("LANG");
284   if (lang == nullptr)
285     return;
286
287   InvokeCallback(lang, IEvent::Type::LANG_CHANGE);
288 }
289
290 void AppCoreBase::RaiseEvent(int event, IEvent::Type type) {
291   impl_->InvokeCallback(event, type);
292 }
293
294 void AppCoreBase::RaiseEvent(const std::string& event, IEvent::Type type) {
295   impl_->InvokeCallback(event, type);
296 }
297
298 void AppCoreBase::Impl::OnFreezerSignal() {
299   if (!allowed_bg_ && suspended_state_) {
300     parent_->RemoveSuspendTimer();
301     InvokeCallback(SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND,
302         IEvent::Type::SUSPENDED_STATE_CHANGE);
303     suspended_state_ = false;
304     parent_->AddSuspendTimer();
305   }
306 }
307
308 AppCoreBase::RotationState AppCoreBase::Impl::GetRm(sensor_data_t data) {
309   if (data.value_count <= 0) {
310     _E("Failed to get sensor data");
311     return ROTATION_UNKNOWN;
312   }
313
314   int event = data.values[0];
315   switch (event) {
316   case AUTO_ROTATION_DEGREE_0:
317     return ROTATION_PORTRAIT_NORMAL;
318   case AUTO_ROTATION_DEGREE_90:
319     return ROTATION_LANDSCAPE_NORMAL;
320   case AUTO_ROTATION_DEGREE_180:
321     return ROTATION_PORTRAIT_REVERSE;
322   case AUTO_ROTATION_DEGREE_270:
323     return ROTATION_LANDSCAPE_REVERSE;
324   default:
325     return ROTATION_UNKNOWN;
326   }
327 }
328
329 void AppCoreBase::Impl::InitSuspendDbusHandler(gpointer data) {
330   if (__suspend_dbus_handler_initialized)
331     return;
332
333   if (__bus == nullptr) {
334     GError* err = nullptr;
335     __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
336     if (__bus == nullptr) {
337       _E("Failed to connect to the D-BUS daemon: %s", err ? err->message : "");
338       if (err)
339         g_error_free(err);
340
341       return;
342     }
343   }
344
345   __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
346     __bus, nullptr, RESOURCED_FREEZER_INTERFACE, RESOURCED_FREEZER_SIGNAL,
347     RESOURCED_FREEZER_PATH, nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
348     ReceiveSuspendSignalCb, data, nullptr);
349
350   if (__suspend_dbus_handler_initialized == 0) {
351     _E("g_dbus_connection_signal_subscribe() is failed.");
352     return;
353   }
354
355   _D("[__SUSPEND__] suspend signal initialized");
356 }
357
358 gboolean AppCoreBase::Impl::InitSuspendCb(gpointer data) {
359   InitSuspendDbusHandler(data);
360   return G_SOURCE_REMOVE;
361 }
362
363 gboolean AppCoreBase::Impl::InvokeLangChangeCb(gpointer data) {
364   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
365   base->impl_->sid_ = 0;
366   base->impl_->ChangeLang();
367   return G_SOURCE_REMOVE;
368 }
369
370 void AppCoreBase::Impl::ReceiveSuspendSignalCb(GDBusConnection*, const gchar*,
371     const gchar*, const gchar*, const gchar* signal_name, GVariant* parameters,
372     gpointer user_data) {
373   if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
374     gint pid = -1;
375     gint status = 0;
376     g_variant_get(parameters, "(ii)", &status, &pid);
377     if (pid == getpid() && status == 0) {
378       AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
379       base->impl_->OnFreezerSignal();
380     }
381   }
382 }
383
384 void AppCoreBase::Impl::LanguageChangeCb(keynode_t* key, void* user_data) {
385   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
386   if (base->impl_->sid_) {
387     GLib::SourceRemove(base->impl_->sid_);
388     base->impl_->sid_ = 0;
389   }
390
391   char* val = vconf_keynode_get_str(key);
392   if (val == nullptr)
393     return;
394
395   base->impl_->UpdateLang();
396   base->impl_->InvokeCallback(val, IEvent::Type::LANG_CHANGE);
397 }
398
399 void AppCoreBase::Impl::RegionChangeCb(keynode_t* key, void* user_data) {
400   const char* name = vconf_keynode_get_name(key);
401   if (name == nullptr)
402     return;
403
404   if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
405       strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
406     return;
407
408   char* val = vconf_get_str(VCONFKEY_REGIONFORMAT);
409   if (val == nullptr)
410     return;
411   std::unique_ptr<char, decltype(std::free)*> region_auto(val, std::free);
412
413   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
414   base->impl_->UpdateRegion();
415   base->impl_->InvokeCallback(val, IEvent::Type::REGION_CHANGE);
416 }
417
418 void AppCoreBase::Impl::LowMemoryCb(keynode_t* key, void* user_data) {
419   int val = vconf_keynode_get_int(key);
420   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
421   base->impl_->InvokeCallback(val, IEvent::Type::LOW_MEMORY);
422   if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
423     malloc_trim(0);
424 }
425
426 void AppCoreBase::Impl::ChargerStatusChangedCb(keynode_t* keynode,
427     void* user_data) {
428   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
429   if (base->impl_->feature_ & FEATURE_CHARGER_STATUS) {
430     __rotation.charger_status = vconf_keynode_get_int(keynode);
431     if (__rotation.ref) {
432       if (__rotation.charger_status) {
433         base->impl_->InitRotation();
434       } else {
435         base->impl_->FiniRotation();
436       }
437     }
438
439     _D("charger status(%d)", __rotation.charger_status);
440   }
441 }
442
443 void AppCoreBase::Impl::LockCb(keynode_t* node, void* user_data) {
444   AppCoreBase::RotationState rm;
445   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
446
447   __rotation.lock = !vconf_keynode_get_bool(node);
448   if (__rotation.lock) {
449     _D("Rotation locked");
450     rm = ROTATION_PORTRAIT_NORMAL;
451   } else {
452     _D("Rotation unlocked");
453     sensor_data_t data;
454     bool r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
455     if (!r) {
456       _E("Failed to get sensor data");
457       return;
458     }
459
460     rm = base->impl_->GetRm(data);
461     if (rm == ROTATION_UNKNOWN) {
462       _E("Unknown mode");
463       return;
464     }
465   }
466
467   if (__rotation.rm == rm)
468     return;
469
470   _D("Rotation: %d -> %d", __rotation.rm, rm);
471   __rotation.rm = rm;
472   base->impl_->InvokeCallback(__rotation.rm,
473       IEvent::Type::DEVICE_ORIENTATION_CHANGED);
474 }
475
476 void AppCoreBase::Impl::AutoRotationChangedCb(sensor_t sensor,
477     unsigned int event_type, sensor_data_t* data, void* user_data) {
478   if (data == nullptr)
479     return;
480
481   if (__rotation.lock)
482     return;
483
484   if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
485     return;
486
487   AppCoreBase* base = reinterpret_cast<AppCoreBase*>(user_data);
488   AppCoreBase::RotationState rm = base->impl_->GetRm(*data);
489   if (rm == ROTATION_UNKNOWN) {
490     _E("Unknown mode");
491     return;
492   }
493
494   _D("Rotation: %d -> %d", __rotation.rm, rm);
495   __rotation.rm = rm;
496   base->impl_->InvokeCallback(__rotation.rm,
497       IEvent::Type::DEVICE_ORIENTATION_CHANGED);
498 }
499
500 void AppCoreBase::Impl::InitRotation() {
501   if (__rotation.initialized)
502     return;
503
504   sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
505   __rotation.conn = sensord_connect(sensor);
506   if (__rotation.conn < 0) {
507     _E("Failed to connect sensord");
508     return;
509   }
510
511   bool r = sensord_register_event(__rotation.conn,
512       AUTO_ROTATION_CHANGE_STATE_EVENT, SENSOR_INTERVAL_NORMAL, 0,
513       AutoRotationChangedCb, parent_);
514   if (!r) {
515     _E("Failed to register auto rotation change event");
516     sensord_disconnect(__rotation.conn);
517     return;
518   }
519
520   r = sensord_start(__rotation.conn, 0);
521   if (!r) {
522     _E("Failed to start sensord");
523     sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
524     sensord_disconnect(__rotation.conn);
525     return;
526   }
527
528   int lock = 0;
529   vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
530   vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb,
531       parent_);
532
533   __rotation.lock = !lock;
534   __rotation.initialized = true;
535 }
536
537 void AppCoreBase::Impl::FiniRotation() {
538   if (!__rotation.initialized)
539     return;
540
541   vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, LockCb);
542   sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
543   sensord_stop(__rotation.conn);
544   sensord_disconnect(__rotation.conn);
545
546   __rotation.lock = 0;
547   __rotation.initialized = false;
548 }
549
550 void AppCoreBase::Impl::VerifyLanguage() {
551   const char* env_lang = getenv("LANG");
552   if (env_lang == nullptr)
553     return;
554
555   char* lang = vconf_get_str(VCONFKEY_LANGSET);
556   if (lang == nullptr)
557     return;
558
559   std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
560
561   if (strcmp(env_lang, lang) != 0) {
562     _I("LANG(%s), LANGSET(%s)", env_lang, lang);
563     sid_ = GLib::IdleAdd(InvokeLangChangeCb, parent_);
564   }
565 }
566
567 void AppCoreBase::Impl::SetDefaultEvents() {
568   vconf_notify_key_changed(VCONFKEY_LANGSET, LanguageChangeCb, parent_);
569   int r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb,
570       parent_);
571   if (r == 0) {
572     vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb,
573         parent_);
574   }
575
576   vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb, parent_);
577 }
578
579 void AppCoreBase::Impl::UnsetDefaultEvents() {
580   vconf_ignore_key_changed(VCONFKEY_LANGSET, LanguageChangeCb);
581   int r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, RegionChangeCb);
582   if (r == 0)
583     vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, RegionChangeCb);
584
585   vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, LowMemoryCb);
586 }
587
588 int AppCoreBase::OnReceive(aul_type type, tizen_base::Bundle b) {
589   switch (type) {
590   case AUL_START:
591     _D("[APP %d]     AUL event: AUL_START", getpid());
592     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
593       std::string bg = b.GetString(AUL_K_ALLOWED_BG);
594       if (bg == "ALLOWED_BG") {
595         _D("[__SUSPEND__] allowed background");
596         impl_->allowed_bg_ = true;
597         RemoveSuspendTimer();
598       }
599     }
600
601     traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
602     if (impl_->core_delegator_)
603       impl_->core_delegator_->OnControl(std::move(b));
604     else
605       OnControl(std::move(b));
606     traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
607     break;
608   case AUL_RESUME:
609     _D("[APP %d]     AUL event: AUL_RESUME", getpid());
610     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
611       std::string bg = b.GetString(AUL_K_ALLOWED_BG);
612       if (bg == "ALLOWED_BG") {
613         _D("[__SUSPEND__] allowed background");
614         impl_->allowed_bg_ = true;
615         RemoveSuspendTimer();
616       }
617     }
618     break;
619   case AUL_TERMINATE:
620     _D("[APP %d]     AUL event: AUL_TERMINATE", getpid());
621     aul_status_update(STATUS_DYING);
622     if (!impl_->allowed_bg_)
623       RemoveSuspendTimer();
624
625     Exit();
626     break;
627   case AUL_TERMINATE_INST:
628   case AUL_TERMINATE_BG_INST:
629   case AUL_TERMINATE_BGAPP:
630     _D("[APP %d]     AUL event: %d", getpid(), type);
631     if (!impl_->allowed_bg_)
632       RemoveSuspendTimer();
633     break;
634   case AUL_WAKE:
635     _D("[APP %d]     AUL event: AUL_WAKE", getpid());
636     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
637       if (!impl_->allowed_bg_ && impl_->suspended_state_) {
638         RemoveSuspendTimer();
639         int suspend = SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
640         impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
641         impl_->suspended_state_ = false;
642       }
643     }
644     break;
645   case AUL_SUSPEND:
646     _D("[APP %d]     AUL event: AUL_SUSPEND", getpid());
647     if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT) {
648       if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
649         RemoveSuspendTimer();
650         FlushMemory();
651       }
652     }
653     break;
654   case AUL_UPDATE_REQUESTED:
655     _D("[APP %d]     AUL event: AUL_UPDATE_REQUESTED", getpid());
656     impl_->InvokeCallback(0, IEvent::Type::UPDATE_REQUESTED);
657     break;
658   default:
659     _D("[APP %d]     AUL event: %d", getpid(), type);
660     /* do nothing */
661     break;
662   }
663
664   return 0;
665 }
666
667 int AppCoreBase::OnCreate() {
668   int ret = aul_launch_init([](aul_type type, bundle* b, void* data) -> int {
669         AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
670         if (base->impl_->core_delegator_) {
671           return base->impl_->core_delegator_->OnReceive(type,
672               b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
673         }
674         return base->OnReceive(type,
675             b ? tizen_base::Bundle(b, false, false) : tizen_base::Bundle());
676       }, this);
677   if (ret < 0 && ret != AUL_R_ECANCELED) {
678     _E("aul_launch_init() is failed. error(%d)", ret);
679     return -1;
680   }
681
682   ret = aul_launch_argv_handler(impl_->argc_, impl_->argv_);
683   if (ret < 0) {
684     _E("aul_launch_argv_handler() is failed. error(%d)", ret);
685     return -1;
686   }
687
688   return 0;
689 }
690
691 int AppCoreBase::OnControl(tizen_base::Bundle b) {
692   return 0;
693 }
694
695 int AppCoreBase::OnTerminate() {
696   aul_finalize();
697   return 0;
698 }
699
700 void AppCoreBase::SetCoreDelegator(IAppCore* delegator) {
701   impl_->core_delegator_ = delegator;
702 }
703
704 void AppCoreBase::SetLoopDelegator(IMainLoop* delegator) {
705   impl_->loop_delegator_ = delegator;
706 }
707
708 std::string AppCoreBase::Impl::GetAppName(const char* appid) {
709   if (appid == nullptr)
710     return "";
711
712   /* com.vendor.name -> name */
713   const char* name_token = strrchr(appid, '.');
714   if (name_token == nullptr)
715     return appid;
716
717   name_token++;
718   return name_token;
719 }
720
721 std::string AppCoreBase::Impl::GetLocaleResourceDir() {
722   const char* res_path = aul_get_app_resource_path();
723   if (res_path == nullptr) {
724     _E("Failed to get resource path");
725     return "";
726   }
727
728   return std::string(res_path) + PATH_LOCALE;
729 }
730
731 int AppCoreBase::OnSetI18n() {
732   char appid[PATH_MAX];
733   int ret = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
734   if (ret < 0) {
735     _E("aul_app_get_appid_bypid() is failed. error(%d)", ret);
736     return -1;
737   }
738
739   std::string name = impl_->GetAppName(appid);
740   if (name.empty())
741     return -1;
742
743   std::string locale_dir = impl_->GetLocaleResourceDir();
744   if (locale_dir.empty())
745     return -1;
746
747   return SetI18n(move(name), move(locale_dir));
748 }
749
750 void AppCoreBase::Impl::OnLowBatteryCb(keynode_t* key, void* data) {
751   int val = vconf_keynode_get_int(key);
752   if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
753     AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
754     base->impl_->InvokeCallback(val, IEvent::Type::LOW_BATTERY);
755   }
756 }
757
758 void AppCoreBase::Impl::OnTimeZoneChangedCb(keynode_t* key, void* data) {
759   char* time_zone_id = vconf_keynode_get_str(key);
760   if (time_zone_id == nullptr) {
761     return;
762   }
763
764   char* time_zone = vconf_get_str(VCONFKEY_SETAPPL_TIMEZONE_INT);
765   if (time_zone != nullptr) {
766     AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
767     base->impl_->InvokeCallback(std::string(time_zone) + "|" + time_zone_id,
768         IEvent::Type::TIME_ZONE_CHANGED);
769     free(time_zone);
770   }
771 }
772
773 void AppCoreBase::Impl::UnregisterRotationChangedEvent() {
774   if (!__rotation.ref)
775     return;
776
777   __rotation.ref--;
778   if (__rotation.ref == 0) {
779     FiniRotation();
780     if (feature_ & FEATURE_CHARGER_STATUS) {
781       vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
782           ChargerStatusChangedCb);
783     }
784   }
785 }
786
787 void AppCoreBase::Impl::RegisterRotationChangedEvent() {
788   if (__rotation.ref == 0) {
789     if (feature_ & FEATURE_CHARGER_STATUS) {
790       vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &__rotation.charger_status);
791       vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
792           ChargerStatusChangedCb, parent_);
793       if (__rotation.charger_status)
794         InitRotation();
795     } else {
796       InitRotation();
797     }
798   }
799
800   __rotation.ref++;
801 }
802
803 int AppCoreBase::OnSetEvent(IEvent::Type event) {
804   switch (event) {
805   case IEvent::Type::LOW_BATTERY:
806     vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
807         impl_->OnLowBatteryCb, this);
808     break;
809   case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
810     impl_->RegisterRotationChangedEvent();
811     break;
812   case IEvent::Type::SUSPENDED_STATE_CHANGE:
813     break;
814   case IEvent::Type::TIME_ZONE_CHANGED:
815     vconf_notify_key_changed(VCONFKEY_SETAPPL_TIMEZONE_ID,
816         impl_->OnTimeZoneChangedCb, this);
817     break;
818   default:
819     break;
820   }
821
822   return 0;
823 }
824
825 int AppCoreBase::OnUnsetEvent(IEvent::Type event) {
826   switch (event) {
827   case IEvent::Type::LOW_BATTERY:
828     vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
829         impl_->OnLowBatteryCb);
830     break;
831   case IEvent::Type::DEVICE_ORIENTATION_CHANGED:
832     impl_->UnregisterRotationChangedEvent();
833     break;
834   case IEvent::Type::SUSPENDED_STATE_CHANGE:
835     break;
836   default:
837     break;
838   }
839
840   return 0;
841 }
842
843 int AppCoreBase::OnTrimMemory() {
844   int (*sqlite3_free_heap_memory)(int);
845
846   sqlite3_free_heap_memory = reinterpret_cast<
847       decltype(sqlite3_free_heap_memory)>(
848           dlsym(RTLD_DEFAULT, "sqlite3_release_memory"));
849   if (sqlite3_free_heap_memory)
850     sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
851
852   malloc_trim(0);
853   return 0;
854 }
855
856 void AppCoreBase::AddEvent(std::shared_ptr<EventBase> event) {
857   bool found = false;
858   for (auto& ev : impl_->events_) {
859     if (ev->GetType() == event->GetType()) {
860       found = true;
861       break;
862     }
863   }
864
865   if (!found) {
866     if (impl_->core_delegator_)
867       impl_->core_delegator_->OnSetEvent(event->GetType());
868     else
869       OnSetEvent(event->GetType());
870   }
871
872   impl_->events_.push_back(move(event));
873 }
874
875 bool AppCoreBase::RemoveEvent(std::shared_ptr<EventBase> event) {
876   bool found = false;
877   impl_->events_.remove_if([&](const std::shared_ptr<EventBase>& ptr)->bool {
878     if (event.get() == ptr.get()) {
879       found = true;
880       return true;
881     }
882     return false;
883   });
884
885   return found;
886 }
887
888 void AppCoreBase::FlushMemory() {
889   if (impl_->core_delegator_)
890     impl_->core_delegator_->OnTrimMemory();
891   else
892     OnTrimMemory();
893
894   impl_->tid_ = 0;
895   if (!impl_->allowed_bg_ && !impl_->suspended_state_) {
896     _D("[__SUSPEND__] flush case");
897     int suspend = SUSPENDED_STATE_WILL_ENTER_SUSPEND;
898     impl_->InvokeCallback(suspend, IEvent::Type::SUSPENDED_STATE_CHANGE);
899     impl_->suspended_state_ = true;
900   }
901 }
902
903 AppCoreBase::RotationState AppCoreBase::GetRotationState() {
904   if (!__rotation.ref)
905     throw std::runtime_error("invalid rotation state");
906
907   return __rotation.rm;
908 }
909
910 bool AppCoreBase::IsBgAllowed() {
911   return impl_->allowed_bg_;
912 }
913
914 bool AppCoreBase::IsSuspended() {
915   return impl_->suspended_state_;
916 }
917
918 void AppCoreBase::ToggleSuspendedState() {
919   impl_->suspended_state_ = !impl_->suspended_state_;
920 }
921
922 std::list<std::string> AppCoreBase::Impl::SplitLanguage(
923     const std::string& lang) {
924   std::istringstream ss(lang);
925   std::list<std::string> li;
926   std::string token;
927
928   while (std::getline(ss, token, ':'))
929     li.push_back(token);
930
931   return li;
932 }
933
934 void AppCoreBase::Impl::AppendDefaultLangs(std::vector<std::string>& langs) {
935   langs.push_back("en_US");
936   langs.push_back("en_GB");
937   langs.push_back("en");
938 }
939
940 std::string AppCoreBase::Impl::GetStringBefore(const char* cstr,
941     const char* delim) {
942   if (cstr == nullptr || delim == nullptr)
943     return "";
944
945   auto str = std::string(cstr);
946   auto idx = str.find(delim);
947   return str.substr(0, idx);
948 }
949
950 std::map<std::string, std::set<std::string>> AppCoreBase::Impl::GetLangTable() {
951   if (locale_dir_.empty())
952     return {};
953
954   DIR* dp = opendir(locale_dir_.c_str());
955   if (dp == nullptr)
956     return {};
957
958   std::map<std::string, std::set<std::string>> table;
959   struct dirent *dentry;
960   while ((dentry = readdir(dp)) != nullptr) {
961     if (!strcmp(dentry->d_name, ".") ||
962         !strcmp(dentry->d_name, ".."))
963       continue;
964
965     std::string buf = locale_dir_ + "/" + dentry->d_name;
966     struct stat stat_buf;
967     int ret = stat(buf.c_str(), &stat_buf);
968     if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
969       continue;
970
971     std::string parent_lang = GetStringBefore(dentry->d_name, "_");
972     if (parent_lang.empty()) {
973       _E("Out of memory");
974       break;
975     }
976
977     table[parent_lang].insert(dentry->d_name);
978   }
979
980   closedir(dp);
981   return table;
982 }
983
984 void AppCoreBase::Impl::AppendLangs(const std::string& lang,
985     std::vector<std::string>& langs,
986     std::map<std::string, std::set<std::string>>& table) {
987   if (lang.empty())
988     return;
989
990   langs.push_back(lang);
991   std::string extract_lang = GetStringBefore(lang.c_str(), ".");
992   if (extract_lang.empty())
993     return;
994
995   if (std::find(langs.begin(), langs.end(), extract_lang) != langs.end())
996     return;
997
998   std::string parent_lang = GetStringBefore(extract_lang.c_str(), "_");
999   if (parent_lang.empty())
1000     return;
1001
1002   if (table.find(parent_lang) == table.end())
1003     return;
1004
1005   auto it = table[parent_lang].find(extract_lang);
1006   if (it != table[parent_lang].end()) {
1007     std::string value = *it;
1008     if (std::find(langs.begin(), langs.end(), value) == langs.end())
1009       langs.push_back(std::move(value));
1010
1011     table[parent_lang].erase(it);
1012     return;
1013   }
1014
1015   it = table[parent_lang].find(parent_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));
1020
1021     table[parent_lang].erase(parent_lang);
1022     return;
1023   }
1024
1025   if (!table[parent_lang].empty()) {
1026     auto i = table[parent_lang].begin();
1027     std::string value = *i;
1028     if (std::find(langs.begin(), langs.end(), value) == langs.end())
1029       langs.push_back(std::move(value));
1030
1031     table[parent_lang].erase(i);
1032   }
1033 }
1034
1035 std::string AppCoreBase::Impl::GetLanguage(std::string lang) {
1036   std::list<std::string> l = SplitLanguage(lang);
1037   if (l.empty())
1038     return "";
1039
1040   auto table = GetLangTable();
1041   if (table.empty())
1042     return "";
1043
1044   std::vector<std::string> langs;
1045   for (auto& i : l)
1046     AppendLangs(i, langs, table);
1047
1048   AppendDefaultLangs(langs);
1049   std::string ret;
1050   for (auto& i : langs) {
1051     if (ret.empty())
1052       ret = i;
1053     else
1054       ret += ":" + i;
1055   }
1056
1057   return ret;
1058 }
1059
1060 void AppCoreBase::Impl::UpdateLang() {
1061   char* lang = vconf_get_str(VCONFKEY_LANGSET);
1062   if (lang == nullptr)
1063     return;
1064
1065   std::unique_ptr<char, decltype(std::free)*> lang_auto(lang, std::free);
1066   std::string language = GetLanguage(lang);
1067   if (!language.empty()) {
1068     _D("*****language(%s)", language.c_str());
1069     setenv("LANGUAGE", language.c_str(), 1);
1070   } else {
1071     setenv("LANGUAGE", lang, 1);
1072   }
1073   setenv("LANG", lang, 1);
1074   setenv("LC_MESSAGES", lang, 1);
1075   setenv("LC_ALL", lang, 1);
1076   char* r = setlocale(LC_ALL, "");
1077   if (r == nullptr) {
1078     r = setlocale(LC_ALL, "en_US.UTF-8");
1079     if (r != nullptr) {
1080       _D("*****appcore setlocale=%s\n", r);
1081     } else {
1082       _D("*****appcore setlocale=\"C\"");
1083       setenv("LC_ALL", "C", 1);
1084       r = setlocale(LC_ALL, "");
1085       if (r == nullptr)
1086         _E("failed to setlocale");
1087     }
1088   }
1089 }
1090
1091 void AppCoreBase::Impl::UpdateRegion() {
1092   char* region = vconf_get_str(VCONFKEY_REGIONFORMAT);
1093   if (region == nullptr)
1094     return;
1095
1096   std::unique_ptr<char, decltype(std::free)*> region_auto(region, std::free);
1097   setenv("LC_CTYPE", region, 1);
1098   setenv("LC_NUMERIC", region, 1);
1099   setenv("LC_TIME", region, 1);
1100   setenv("LC_COLLATE", region, 1);
1101   setenv("LC_MONETARY", region, 1);
1102   setenv("LC_PAPER", region, 1);
1103   setenv("LC_NAME", region, 1);
1104   setenv("LC_ADDRESS", region, 1);
1105   setenv("LC_TELEPHONE", region, 1);
1106   setenv("LC_MEASUREMENT", region, 1);
1107   setenv("LC_IDENTIFICATION", region, 1);
1108   char* r = setlocale(LC_ALL, "");
1109   if (r != nullptr) {
1110     _D("*****appcore setlocale=%s\n", r);
1111   } else {
1112     _D("*****appcore setlocale=\"C\"");
1113     setenv("LC_ALL", "C", 1);
1114     r = setlocale(LC_ALL, "");
1115     if (r == nullptr)
1116       _E("failed to setlocale");
1117   }
1118 }
1119
1120 int AppCoreBase::SetI18n(std::string domain_name, std::string dir_name) {
1121   if (domain_name.empty()) {
1122     errno = EINVAL;
1123     return -1;
1124   }
1125
1126   if (!dir_name.empty())
1127     impl_->locale_dir_ = dir_name;
1128
1129   impl_->UpdateLang();
1130   impl_->UpdateRegion();
1131
1132   char* r = setlocale(LC_ALL, "");
1133   /* if locale is not set properly, try to set "en_US" again */
1134   if (r == nullptr) {
1135     r = setlocale(LC_ALL, "en_US.UTF-8");
1136     if (r == nullptr) {
1137       _E("appcore: setlocale() error");
1138       _D("*****appcore setlocale=\"C\"");
1139       setenv("LC_ALL", "C", 1);
1140       r = setlocale(LC_ALL, "");
1141       if (r == nullptr)
1142         _E("failed to setlocale");
1143     }
1144   }
1145
1146   if (r != nullptr)
1147     _D("*****appcore setlocale=%s\n", r);
1148
1149   r = bindtextdomain(domain_name.c_str(), dir_name.c_str());
1150   if (r == nullptr)
1151     _E("appcore: bindtextdomain() error");
1152
1153   r = textdomain(domain_name.c_str());
1154   if (r == nullptr)
1155     _E("appcore: textdomain() error");
1156
1157   return 0;
1158 }
1159
1160 void AppCoreBase::Exit() {
1161   aul_status_update(STATUS_DYING);
1162   if (impl_->loop_delegator_)
1163     impl_->loop_delegator_->OnLoopExit();
1164   else
1165     OnLoopExit();
1166 }
1167
1168 void AppCoreBase::AddSuspendTimer() {
1169   impl_->tid_ = GLib::TimeoutAdd(5000, [](gpointer data) -> gboolean {
1170         AppCoreBase* base = reinterpret_cast<AppCoreBase*>(data);
1171         base->FlushMemory();
1172         return FALSE;
1173       }, this);
1174 }
1175
1176 void AppCoreBase::RemoveSuspendTimer() {
1177   if (impl_->tid_ > 0) {
1178     GLib::SourceRemove(impl_->tid_);
1179     impl_->tid_ = 0;
1180   }
1181 }
1182
1183 void AppCoreBase::SetDisplayState(DisplayState state) {
1184   __display_state = state;
1185 }
1186
1187 AppCoreBase::DisplayState AppCoreBase::GetDisplayState() {
1188   return __display_state;
1189 }
1190
1191 int AppCoreBase::EnableWatchdog() {
1192   _I("[__APPCORE_WATCHDOG__] enable");
1193   return aul_watchdog_enable();
1194 }
1195
1196 int AppCoreBase::DisableWatchdog() {
1197   _I("[__APPCORE_WATCHDOG__] disable");
1198   return aul_watchdog_disable();
1199 }
1200
1201 int AppCoreBase::KickWatchdog() {
1202   _I("[__APPCORE_WATCHDOG__] kick");
1203   return aul_watchdog_kick();
1204 }
1205
1206 void AppCoreBase::Run(int argc, char** argv) {
1207   Init(argc, argv);
1208   Fini();
1209 }
1210
1211 void AppCoreBase::Init(int argc, char** argv) {
1212   impl_->tid_ = 0;
1213   impl_->suspended_state_ = false;
1214   impl_->allowed_bg_ = false;
1215   impl_->argc_ = argc;
1216   impl_->argv_ = argv;
1217   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:OPS_INIT");
1218   sigterm_handler.Restore();
1219   if (impl_->loop_delegator_)
1220     impl_->loop_delegator_->OnLoopInit(argc, argv);
1221   else
1222     OnLoopInit(argc, argv);
1223
1224   impl_->signal_handler_source_ = g_unix_signal_add(SIGTERM,
1225       [](gpointer data) -> gboolean {
1226         _W("sigterm handler");
1227         if (context_ != nullptr) {
1228           context_->Exit();
1229           context_->impl_->signal_handler_source_ = 0;
1230         }
1231
1232         return G_SOURCE_REMOVE;
1233       }, nullptr);
1234
1235   if (impl_->signal_handler_source_ == 0)
1236     _E("Failed to add sigterm handler.");
1237
1238   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1239
1240   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:PLUGIN_INIT");
1241   impl_->PluginInit(argc, argv);
1242   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1243
1244   if (impl_->feature_ & FEATURE_BACKGROUND_MANAGEMENT)
1245     GLib::IdleAdd(Impl::InitSuspendCb, this);
1246
1247   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_SYSTEM_EVENT");
1248   if (!impl_->dirty_) {
1249     impl_->dirty_ = true;
1250
1251     for (auto& e : impl_->events_) {
1252       if (impl_->core_delegator_)
1253         impl_->core_delegator_->OnSetEvent(e->GetType());
1254       else
1255         OnSetEvent(e->GetType());
1256     }
1257   }
1258   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1259
1260   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:VERIFY_LANG");
1261   impl_->VerifyLanguage();
1262   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1263
1264   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:SET_DEFAULT_EVENTS");
1265   impl_->SetDefaultEvents();
1266   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1267
1268   if (impl_->core_delegator_)
1269     impl_->core_delegator_->OnSetI18n();
1270   else
1271     OnSetI18n();
1272
1273   aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_INITIALIZED);
1274
1275   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1276   int create = 0;
1277   if (impl_->core_delegator_)
1278     create = impl_->core_delegator_->OnCreate();
1279   else
1280     create = OnCreate();
1281   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1282
1283   aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_CREATED);
1284   if (create < 0)
1285     return;
1286
1287   if (impl_->loop_delegator_)
1288     impl_->loop_delegator_->OnLoopRun();
1289   else
1290     OnLoopRun();
1291 }
1292
1293 void AppCoreBase::Fini() {
1294   if (impl_->signal_handler_source_) {
1295     g_source_remove(impl_->signal_handler_source_);
1296     impl_->signal_handler_source_ = 0;
1297   }
1298
1299   Dispose();
1300 }
1301
1302 void AppCoreBase::Dispose() {
1303   aul_status_update(STATUS_DYING);
1304   DisableWatchdog();
1305   aul_app_lifecycle_update_state(AUL_APP_LIFECYCLE_STATE_DESTROYED);
1306
1307   traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1308   if (impl_->core_delegator_)
1309     impl_->core_delegator_->OnTerminate();
1310   else
1311     OnTerminate();
1312   traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1313
1314   for (auto& e : impl_->events_) {
1315     if (impl_->core_delegator_)
1316       impl_->core_delegator_->OnUnsetEvent(e->GetType());
1317     else
1318       OnUnsetEvent(e->GetType());
1319   }
1320
1321   impl_->UnsetDefaultEvents();
1322   if (impl_->sid_) {
1323     GLib::SourceRemove(impl_->sid_);
1324     impl_->sid_ = 0;
1325   }
1326
1327   RemoveSuspendTimer();
1328   impl_->PluginFini();
1329   impl_->dirty_ = false;
1330   if (impl_->loop_delegator_)
1331     impl_->loop_delegator_->OnLoopFinish();
1332   else
1333     OnLoopFinish();
1334 }
1335
1336 void AppCoreBase::SetFeature(int feature) {
1337   impl_->feature_ = feature;
1338 }
1339
1340 int AppCoreBase::GetFeature() const {
1341   return impl_->feature_;
1342 }
1343
1344 void AppCoreBase::Impl::PluginInit(int argc, char** argv) {
1345   plugin_.reset(AppCorePlugin::Load());
1346   if (!plugin_)
1347     return;
1348
1349   plugin_->Init(argc, argv);
1350 }
1351
1352 void AppCoreBase::Impl::PluginFini() {
1353   if (!plugin_)
1354     return;
1355
1356   plugin_->Fini();
1357 }
1358
1359 }  // namespace tizen_cpp