Fix for race condition issue when widget is pausing
[platform/framework/web/wrt.git] / src / wrt-client / wrt-client.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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 #include "wrt-client.h"
17 #include <appcore-efl.h>
18 #include <appcore-common.h>
19 #include <cstdlib>
20 #include <cstdio>
21 #include <string>
22 #include <dpl/log/log.h>
23 #include <dpl/optional_typedefs.h>
24 #include <dpl/exception.h>
25 #include <common/application_data.h>
26 #include <core_module.h>
27 #include <localization_setting.h>
28 #include <widget_deserialize_model.h>
29 #include <EWebKit2.h>
30 #include <dpl/localization/w3c_file_localization.h>
31 #include <dpl/localization/LanguageTagsProvider.h>
32 #include "webkit/bundles/plugin_module_support.h"
33
34 //W3C PACKAGING enviroment variable name
35 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
36
37 // window signal callback
38 const char *EDJE_SHOW_BACKWARD_SIGNAL = "show,backward,signal";
39 const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
40 const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized";
41 char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content";
42 const char* const BUNDLE_PATH = "/usr/lib/wrt-wk2-bundles/libwrt-wk2-bundle.so";
43
44 static Ewk_Context* s_ewk_context = NULL;
45
46 WrtClient::WrtClient(int argc, char **argv) :
47     Application(argc, argv, "wrt-client", false),
48     DPL::TaskDecl<WrtClient>(this),
49     m_launched(false),
50     m_initializing(false),
51     m_initialized(false),
52     m_sdkLauncherPid(0),
53     m_debugMode(false),
54     m_debuggerPort(0),
55     m_returnStatus(ReturnStatus::Succeeded),
56     m_widgetState(WidgetState::WidgetState_Stopped)
57 {
58     Touch();
59     LogDebug("App Created");
60 }
61
62 WrtClient::~WrtClient()
63 {
64     LogDebug("App Finished");
65 }
66
67 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
68 {
69     return m_returnStatus;
70 }
71
72 void WrtClient::OnStop()
73 {
74     LogInfo("Stopping Dummy Client");
75 }
76
77 void WrtClient::OnCreate()
78 {
79     LogInfo("On Create");
80     ADD_PROFILING_POINT("OnCreate callback", "point");
81     ewk_init();
82 }
83
84 void WrtClient::OnResume()
85 {
86     if (m_widgetState != WidgetState_Suspended) {
87         LogWarning("Widget is not suspended, resuming was skipped");
88         return;
89     }
90     m_widget->Resume();
91     m_widgetState = WidgetState_Running;
92 }
93
94 void WrtClient::OnPause()
95 {
96     if (m_widgetState != WidgetState_Running) {
97         LogWarning("Widget is not running to be suspended");
98         return;
99     }
100     m_widget->Suspend();
101     m_widgetState = WidgetState_Suspended;
102 }
103
104 void WrtClient::OnReset(bundle *b)
105 {
106     LogDebug("OnReset");
107     // bundle argument is freed after OnReset() is returned
108     // So bundle duplication is needed
109     ApplicationDataSingleton::Instance().setBundle(bundle_dup(b));
110
111     if (true == m_initializing) {
112         LogDebug("can not handle reset event");
113         return;
114     }
115     if (true == m_launched) {
116         if (m_widgetState == WidgetState_Stopped) {
117             LogError("Widget is not running to be reset");
118             return;
119         }
120         m_widget->Reset();
121         m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
122         m_widgetState = WidgetState_Running;
123     } else {
124         if (true == checkArgument()) {
125             setStep();
126         } else {
127             showHelpAndQuit();
128         }
129     }
130
131     // low memory callback set
132     appcore_set_event_callback(
133             APPCORE_EVENT_LOW_MEMORY,
134             WrtClient::appcoreLowMemoryCallback,
135             this);
136 }
137
138 void WrtClient::OnTerminate()
139 {
140     LogDebug("Wrt Shutdown now");
141     shutdownStep();
142 }
143
144 void WrtClient::showHelpAndQuit()
145 {
146     printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
147            "launch widgets.\n"
148            "Mandatory arguments to long options are mandatory for short "
149            "options too.\n"
150            "  -h,    --help                                 show this help\n"
151            "  -l,    --launch                               "
152            "launch widget with given tizen ID\n"
153            "  -t,    --tizen                                "
154            "launch widget with given tizen ID\n"
155            "\n");
156
157     Quit();
158 }
159
160 bool WrtClient::checkArgument()
161 {
162     std::string tizenId = getTizenIdFromArgument(m_argc, m_argv);
163
164     if (tizenId.empty()) {
165         // Just show help
166         return false;
167     } else {
168         m_tizenId = tizenId;
169         LogDebug("Tizen id: " << m_tizenId);
170         return true;
171     }
172 }
173
174 std::string WrtClient::getTizenIdFromArgument(int argc, char **argv)
175 {
176     LogInfo("checkArgument");
177     std::string arg = argv[0];
178
179     if (arg.empty()) {
180         return "";
181     }
182
183     if (arg.find("wrt-client") != std::string::npos) {
184         if (argc <= 1) {
185             return "";
186         }
187
188         arg = argv[1];
189
190         if (arg == "-h" || arg == "--help") {
191             return "";
192         } else if (arg == "-l" || arg == "--launch" ||
193                    arg == "-t" || arg == "--tizen")
194         {
195             if (argc != 3) {
196                 return "";
197             }
198             return argv[2];
199         } else {
200             return "";
201         }
202     } else {
203         // Launch widget based on application basename
204         size_t pos = arg.find_last_of('/');
205
206         if (pos != std::string::npos) {
207             arg = arg.erase(0, pos + 1);
208         }
209
210         return arg;
211     }
212 }
213
214 void WrtClient::setStep()
215 {
216     LogInfo("setStep");
217
218     AddStep(&WrtClient::initStep);
219
220     setSdkLauncherDebugData();
221
222     AddStep(&WrtClient::launchStep);
223     AddStep(&WrtClient::shutdownStep);
224
225     m_initializing = true;
226
227     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
228 }
229
230 void WrtClient::setSdkLauncherDebugData()
231 {
232     LogDebug("setSdkLauncherDebugData");
233
234     /* check bundle from sdk launcher */
235     bundle *bundleFromSdkLauncher;
236     bundleFromSdkLauncher = bundle_import_from_argv(m_argc, m_argv);
237     const char *bundle_debug = bundle_get_val(bundleFromSdkLauncher, "debug");
238     const char *bundle_pid = bundle_get_val(bundleFromSdkLauncher, "pid");
239     if (bundle_debug != NULL && bundle_pid != NULL) {
240         if (strcmp(bundle_debug, "true") == 0) {
241             m_debugMode = true;
242             m_sdkLauncherPid = atoi(bundle_pid);
243         } else {
244             m_debugMode = false;
245         }
246     }
247     bundle_free(bundleFromSdkLauncher);
248 }
249
250 bool WrtClient::checkDebugMode(SDKDebugData* debugData)
251 {
252     LogError("Checking for debug mode");
253     Assert(m_dao);
254
255     bool debugMode = debugData->debugMode;
256
257     LogInfo("[DEBUG_MODE] Widget is launched in " <<
258             (debugMode ? "DEBUG" : "RETAIL") <<
259             " mode.");
260
261     if (debugMode == true) {
262         // In WAC widget, only test widgets can use web inspector.
263         // In TIZEN widget,
264         // every launched widgets as debug mode can use it.
265         if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_WAC20) {
266             bool developerMode =
267                 WRT::CoreModuleSingleton::Instance().developerMode();
268             //This code will be activated
269             //after WAC test certificate is used by SDK
270             //bool isTestWidget = view->m_widgetModel->IsTestWidget.Get();
271             //if(!isTestWidget)
272             //{
273             //    LogInfo("This is not WAC Test Widget");
274             //    break;
275             //}
276             if (!developerMode) {
277                 LogInfo("This is not WAC Developer Mode");
278                 debugMode = false;
279             }
280         }
281     }
282     return debugMode;
283 }
284
285 void WrtClient::OnEventReceived(const NextStepEvent& /*event*/)
286 {
287     LogDebug("Executing next step");
288     NextStep();
289 }
290
291 void WrtClient::initStep()
292 {
293     LogDebug("");
294     if (WRT::CoreModuleSingleton::Instance().Init()) {
295         m_initialized = true;
296     } else {
297         m_returnStatus = ReturnStatus::Failed;
298         SwitchToStep(&WrtClient::shutdownStep);
299     }
300
301     // ecore_event_jobs are processed sequentially without concession to
302     // other type events. To give a chance of execute to other events,
303     // ecore_timer_add was used.
304     DPL::Event::ControllerEventHandler<NextStepEvent>::PostTimedEvent(
305         NextStepEvent(), 0.001);
306 }
307
308 bool WrtClient::checkWACTestCertififedWidget()
309 {
310     // WAC Waikiki Beta Release Core Specification: Widget Runtime
311     // 10 Dec 2010
312     //
313     // WR-4710 The WRT MUST enable debug functions only for WAC test widgets
314     // i.e. the functions must not be usable for normal WAC widgets, even when
315     // a WAC test widget is executing.
316     ADD_PROFILING_POINT("DeveloperModeCheck", "start");
317     Assert(!!m_dao);
318     // WAC test widget
319     // A widget signed with a WAC-issued test certificate as described in
320     // Developer Mode.
321
322     bool developerWidget = m_dao->isTestWidget();
323     bool developerMode = WRT::CoreModuleSingleton::Instance().developerMode();
324
325     LogDebug("Is WAC test widget: " << developerWidget);
326     LogDebug("Is developer Mode: " << developerMode);
327
328     if (developerWidget) {
329         if (!developerMode) {
330             LogError("WAC test certified developer widget is needed for " <<
331                      "developer mode");
332             return false;
333         } else {
334             //TODO: WR-4660 (show popup about developer widget
335             //      during launch
336             LogInfo("POPUP: THIS IS TEST WIDGET!");
337         }
338     }
339     ADD_PROFILING_POINT("DeveloperModeCheck", "stop");
340     return true;
341 }
342
343 void WrtClient::loadFinishCallback(Evas_Object* webview)
344 {
345     ADD_PROFILING_POINT("loadFinishCallback", "start");
346     SDKDebugData* debug = new SDKDebugData;
347     debug->debugMode = m_debugMode;
348     debug->pid = new unsigned long(getpid());
349
350     LogInfo("Post result of launch");
351
352     // Start inspector server, if current mode is debugger mode.
353     // In the WK2 case, ewk_view_inspector_server_start should
354     // be called after WebProcess is created.
355     if (checkDebugMode(debug)) {
356         debug->portnum =
357             ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0);
358         if (debug->portnum == 0) {
359             LogWarning("Failed to get portnum");
360         } else {
361             LogInfo("Assigned port number for inspector : "
362                     << debug->portnum);
363         }
364     } else {
365         LogDebug("Debug mode is disabled");
366     }
367
368     //w3c packaging test debug (message on 4>)
369     const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE);
370     if (makeScreen != NULL && strcmp(makeScreen, "1") == 0) {
371         FILE* doutput = fdopen(4, "w");
372         fprintf(doutput, "didFinishLoadForFrameCallback: ready\n");
373         fclose(doutput);
374     }
375
376     if (webview) {
377         LogDebug("Launch succesfull");
378
379         m_launched = true;
380         m_initializing = false;
381         setlinebuf(stdout);
382         ADD_PROFILING_POINT("loadFinishCallback", "stop");
383         printf("launched\n");
384         fflush(stdout);
385     } else {
386         printf("failed\n");
387
388         m_returnStatus = ReturnStatus::Failed;
389         //shutdownStep
390         DPL::Event::ControllerEventHandler<NextStepEvent>::
391             PostEvent(NextStepEvent());
392     }
393
394     if (debug->debugMode) {
395         LogDebug("Send RT signal to wrt-launcher(pid: " << m_sdkLauncherPid);
396         union sigval sv;
397         /* send real time signal with result to wrt-launcher */
398         if (webview) {
399             LogDebug("userData->portnum : " << debug->portnum);
400             sv.sival_int = debug->portnum;
401         } else {
402             sv.sival_int = -1;
403         }
404         sigqueue(m_sdkLauncherPid, SIGRTMIN, sv);
405     }
406
407     ApplicationDataSingleton::Instance().freeBundle();
408
409     LogDebug("Cleaning wrtClient launch resources...");
410     delete debug->pid;
411     delete debug;
412 }
413
414 void WrtClient::progressFinishCallback()
415 {
416     m_splashScreen->stopSplashScreen();
417 }
418
419 void WrtClient::webkitExitCallback()
420 {
421     LogDebug("window close called, terminating app");
422     SwitchToStep(&WrtClient::shutdownStep);
423     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
424         NextStepEvent());
425 }
426
427 void WrtClient::webCrashCallback()
428 {
429     LogError("webProcess crashed");
430     SwitchToStep(&WrtClient::shutdownStep);
431     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
432         NextStepEvent());
433 }
434
435 void WrtClient::launchStep()
436 {
437     ADD_PROFILING_POINT("launchStep", "start");
438     LogDebug("Launching widget ...");
439
440     ADD_PROFILING_POINT("getRunnableWidgetObject", "start");
441     m_widget = WRT::CoreModuleSingleton::Instance()
442             .getRunnableWidgetObject(m_tizenId);
443     ADD_PROFILING_POINT("getRunnableWidgetObject", "stop");
444
445     if (!m_widget) {
446         LogError("RunnableWidgetObject is NULL, stop launchStep");
447         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
448             NextStepEvent());
449         return;
450     }
451
452     if (m_widgetState == WidgetState_Running) {
453         LogWarning("Widget already running, stop launchStep");
454         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
455             NextStepEvent());
456         return;
457     }
458
459     if (m_widgetState == WidgetState_Authorizing) {
460         LogWarning("Widget already authorizing, stop launchStep");
461         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
462             NextStepEvent());
463         return;
464     }
465
466     m_dao.reset(new WrtDB::WidgetDAOReadOnly(DPL::FromASCIIString(m_tizenId)));
467     DPL::Optional<DPL::String> defloc = m_dao->getDefaultlocale();
468     if (!defloc.IsNull()) {
469         LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
470             *defloc);
471     }
472
473     // For localizationsetting not changed on widget running
474     //LocalizationSetting::SetLanguageChangedCallback(
475     //        languageChangedCallback, this);
476
477     ADD_PROFILING_POINT("CreateWindow", "start");
478     m_windowData.reset(new WindowData(static_cast<unsigned long>(getpid()),
479                                       true));
480     ADD_PROFILING_POINT("CreateWindow", "stop");
481
482     WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
483     ADD_PROFILING_POINT("Create splash screen", "start");
484     m_splashScreen.reset(
485         new SplashScreenSupport(m_windowData->m_win));
486     if (m_splashScreen->createSplashScreen(m_dao->getSplashImgSrc())) {
487         m_splashScreen->startSplashScreen();
488         cbs->progressFinish = DPL::MakeDelegate(
489                 this,
490                 &WrtClient::
491                     progressFinishCallback);
492     }
493     ADD_PROFILING_POINT("Create splash screen", "stop");
494     DPL::OptionalString startUrl = W3CFileLocalization::getStartFile(m_dao);
495     if (!m_widget->PrepareView(DPL::ToUTF8String(*startUrl),
496             m_windowData->m_win, s_ewk_context))
497     {
498         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
499             NextStepEvent());
500         return;
501     }
502     //you can't show window with splash screen before PrepareView
503     //ewk_view_add_with_context() in viewLogic breaks window
504
505     m_windowData->init();
506
507     WrtDB::WidgetLocalizedInfo localizedInfo =
508         W3CFileLocalization::getLocalizedInfo(m_dao);
509     std::string name = "";
510     if (!(localizedInfo.name.IsNull())) {
511         name = DPL::ToUTF8String(*(localizedInfo.name));
512     }
513     elm_win_title_set(m_windowData->m_win, name.c_str());
514     evas_object_show(m_windowData->m_win);
515     initializeWindowModes();
516     connectElmCallback();
517
518     if (!checkWACTestCertififedWidget()) {
519         LogWarning("WAC Certificate failed, stop launchStep");
520         return;
521     }
522
523     m_widgetState = WidgetState_Authorizing;
524     if (!m_widget->CheckBeforeLaunch()) {
525         LogError("CheckBeforeLaunch failed, stop launchStep");
526         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
527             NextStepEvent());
528         return;
529     }
530     LogInfo("Widget launch accepted. Entering running state");
531     m_widgetState = WidgetState_Running;
532
533     cbs->loadFinish = DPL::MakeDelegate(this, &WrtClient::loadFinishCallback);
534     cbs->bufferSet = DPL::MakeDelegate(this, &WrtClient::setLayout);
535     cbs->bufferUnset = DPL::MakeDelegate(this, &WrtClient::unsetLayout);
536     cbs->webkitExit = DPL::MakeDelegate(this, &WrtClient::webkitExitCallback);
537     cbs->webCrash = DPL::MakeDelegate(this, &WrtClient::webCrashCallback);
538     cbs->toggleFullscreen = DPL::MakeDelegate(
539             m_windowData.get(), &WindowData::toggleFullscreen);
540
541     m_widget->SetUserDelegates(cbs);
542     m_widget->Show();
543     m_windowData->emitSignalForUserLayout(EDJE_SHOW_BACKWARD_SIGNAL, "");
544     ADD_PROFILING_POINT("launchStep", "stop");
545 }
546
547 void WrtClient::initializeWindowModes()
548 {
549     Assert(m_windowData);
550     Assert(m_dao);
551     auto windowModes = m_dao->getWindowModes();
552     bool fullscreen = false;
553     bool backbutton = false;
554     if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
555         WidgetSettings widgetSettings;
556         m_dao->getWidgetSettings(widgetSettings);
557         WidgetSettingList settings(widgetSettings);
558         backbutton =
559             (settings.getBackButtonPresence() == BackButton_Enable);
560     }
561
562     FOREACH(it, windowModes)
563     {
564         std::string viewMode = DPL::ToUTF8String(*it);
565         if (viewMode == VIEWMODE_TYPE_FULLSCREEN) {
566             fullscreen = true;
567             break;
568         } else if (viewMode == VIEWMODE_TYPE_MAXIMIZED) {
569             break;
570         }
571     }
572
573     m_windowData->setViewMode(fullscreen,
574                               backbutton);
575 }
576
577 void WrtClient::backButtonCallback(void* data,
578                                    Evas_Object * /*obj*/,
579                                    void * /*event_info*/)
580 {
581     LogInfo("BackButtonCallback");
582     Assert(data);
583
584     WrtClient* This = static_cast<WrtClient*>(data);
585
586     This->m_widget->Backward();
587 }
588
589 int WrtClient::appcoreLowMemoryCallback(void* /*data*/)
590 {
591     LogInfo("appcoreLowMemoryCallback");
592     //WrtClient* This = static_cast<WrtClient*>(data);
593
594     // TODO call RunnableWidgetObject API regarding low memory
595     // The API should be implemented
596
597     return 0;
598 }
599
600 void WrtClient::connectElmCallback()
601 {
602     Assert(m_windowData);
603     Assert(m_dao);
604     if (m_dao->getWidgetType().appType == WrtDB::APP_TYPE_TIZENWEBAPP) {
605         WidgetSettings widgetSettings;
606         m_dao->getWidgetSettings(widgetSettings);
607         WidgetSettingList settings(widgetSettings);
608         if (settings.getBackButtonPresence() == BackButton_Enable) {
609             m_windowData->addFloatBackButtonCallback(
610                 "clicked",
611                 &WrtClient::backButtonCallback,
612                 this);
613         }
614
615         WidgetSettingScreenLock rotationValue = settings.getRotationValue();
616         if (rotationValue == Screen_Portrait) {
617             elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
618             ewk_view_orientation_send(m_widget->GetCurrentWebview(), 0);
619         } else if (rotationValue == Screen_Landscape) {
620             elm_win_rotation_with_resize_set(m_windowData->m_win, 270);
621             ewk_view_orientation_send(m_widget->GetCurrentWebview(), 90);
622         } else {
623             elm_win_rotation_with_resize_set(m_windowData->m_win, 0);
624             ewk_view_orientation_send(m_widget->GetCurrentWebview(), 0);
625         }
626     }
627 }
628
629 void WrtClient::setLayout(Evas_Object* newBuffer)
630 {
631     LogDebug("add new webkit buffer to window");
632     Assert(newBuffer);
633
634     elm_object_part_content_set(m_windowData->m_user_layout,
635                                 ELM_SWALLOW_CONTENT,
636                                 newBuffer);
637
638     evas_object_show(newBuffer);
639 }
640
641 void WrtClient::unsetLayout(Evas_Object* currentBuffer)
642 {
643     LogDebug("remove current webkit buffer from window");
644     Assert(currentBuffer);
645     evas_object_hide(currentBuffer);
646
647     elm_object_part_content_unset(m_windowData->m_user_layout,
648                                   ELM_SWALLOW_CONTENT);
649 }
650
651 void WrtClient::shutdownStep()
652 {
653     LogDebug("Closing Wrt connection ...");
654
655     if (m_widget && m_widgetState) {
656         m_widgetState = WidgetState_Stopped;
657         m_widget->Hide();
658         m_widget.reset();
659         ewk_context_delete(s_ewk_context);
660         WRT::CoreModuleSingleton::Instance().Terminate();
661     }
662     if (m_initialized) {
663         m_initialized = false;
664     }
665     m_windowData.reset();
666     Quit();
667 }
668
669 int WrtClient::languageChangedCallback(void *data)
670 {
671     LogDebug("Language Changed");
672     if (!data) {
673         return 0;
674     }
675     WrtClient* wrtClient = static_cast<WrtClient*>(data);
676     if (!(wrtClient->m_dao)) {
677         return 0;
678     }
679
680     // reset function fetches system locales and recreates language tags
681     LanguageTagsProviderSingleton::Instance().resetLanguageTags();
682     // widget default locales are added to language tags below
683     DPL::OptionalString defloc = wrtClient->m_dao->getDefaultlocale();
684     if (!defloc.IsNull()) {
685         LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
686             *defloc);
687     }
688
689     if (wrtClient->m_launched &&
690         wrtClient->m_widgetState != WidgetState_Stopped)
691     {
692         wrtClient->m_widget->ReloadStartPage();
693     }
694     return 0;
695 }
696
697 void WrtClient::Quit()
698 {
699     ewk_shutdown();
700     DPL::Application::Quit();
701 }
702
703 int main(int argc,
704          char *argv[])
705 {
706     UNHANDLED_EXCEPTION_HANDLER_BEGIN
707     {
708         ADD_PROFILING_POINT("main-entered", "point");
709
710         // Set log tagging
711         DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
712
713         // set evas backend type
714         if (!getenv("ELM_ENGINE")) {
715             if (!setenv("ELM_ENGINE", "gl", 1)) {
716                 LogDebug("Enable backend");
717             }
718         } else {
719             LogDebug("ELM_ENGINE : " << getenv("ELM_ENGINE"));
720         }
721
722     #ifndef TIZEN_PUBLIC
723         setenv("COREGL_FASTPATH", "1", 1);
724     #endif
725         setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
726         setenv("CAIRO_GL_LAZY_FLUSHING", "yes", 1);
727         setenv("ELM_IMAGE_CACHE", "0", 1);
728
729         // This code is to fork a web process without exec.
730         std::string tizenId = WrtClient::getTizenIdFromArgument(argc, argv);
731
732         if (!tizenId.empty()) {
733             LogDebug("Launching by fork mode");
734             // Language env setup
735             appcore_set_i18n("wrt-client", NULL);
736             ewk_init();
737             ewk_set_arguments(argc, argv);
738             setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
739             s_ewk_context = ewk_context_new_with_injected_bundle_path(
740                     BUNDLE_PATH);
741
742             // plugin init
743             PluginModuleSupport::init(s_ewk_context, tizenId);
744         }
745
746         // Output on stdout will be flushed after every newline character,
747         // even if it is redirected to a pipe. This is useful for running
748         // from a script and parsing output.
749         // (Standard behavior of stdlib is to use full buffering when
750         // redirected to a pipe, which means even after an end of line
751         // the output may not be flushed).
752         setlinebuf(stdout);
753
754         WrtClient app(argc, argv);
755
756         ADD_PROFILING_POINT("Before appExec", "point");
757         int ret = app.Exec();
758         LogDebug("App returned: " << ret);
759         ret = app.getReturnStatus();
760         LogDebug("WrtClient returned: " << ret);
761         return ret;
762     }
763     UNHANDLED_EXCEPTION_HANDLER_END
764 }