Drop root permission when launching apps in command line
[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 <aul.h>
18 #include <sys/time.h>
19 #include <sys/resource.h>
20 #include <appcore-efl.h>
21 #include <appcore-common.h>
22 #include <cstdlib>
23 #include <cstdio>
24 #include <string>
25 #include <dpl/log/log.h>
26 #include <dpl/optional_typedefs.h>
27 #include <dpl/exception.h>
28 #include <application_data.h>
29 #include <core_module.h>
30 #include <localization_setting.h>
31 #include <widget_deserialize_model.h>
32 #include <EWebKit2.h>
33 #include <dpl/localization/w3c_file_localization.h>
34 #include <dpl/localization/LanguageTagsProvider.h>
35 #include <popup-runner/PopupInvoker.h>
36 #include <prepare_external_storage.h>
37 #include <vconf.h>
38 #include "auto_rotation_support.h"
39
40 #include <process_pool.h>
41 #include <process_pool_launchpad_util.h>
42
43 #include "client_command_line_parser.h"
44 #include "client_ide_support.h"
45 #include "client_security_support.h"
46 #include "client_service_support.h"
47 #include "client_submode_support.h"
48
49 //W3C PACKAGING enviroment variable name
50 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
51
52 // window signal callback
53 const char *EDJE_SHOW_PROGRESS_SIGNAL = "show,progress,signal";
54 const char *EDJE_HIDE_PROGRESS_SIGNAL = "hide,progress,signal";
55 const std::string VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
56 const std::string VIEWMODE_TYPE_MAXIMIZED = "maximized";
57 const std::string VIEWMODE_TYPE_WINDOWED = "windowed";
58 char const* const ELM_SWALLOW_CONTENT = "elm.swallow.content";
59 const char* const BUNDLE_PATH = LIBDIR_PREFIX "/usr/lib/libwrt-injected-bundle.so";
60 const char* const MESSAGE_NAME_INITIALIZE = "ToInjectedBundle::INIT";
61 const unsigned int UID_ROOT = 0;
62
63 // process pool
64 const char* const DUMMY_PROCESS_PATH = "/usr/bin/wrt_launchpad_daemon_candidate";
65 static Ewk_Context* s_preparedEwkContext = NULL;
66 static WindowData*  s_preparedWindowData = NULL;
67 static int    app_argc = 0;
68 static char** app_argv = NULL;
69
70 // env
71 const char* const HOME = "HOME";
72 const char* const APP_HOME_PATH = "/opt/home/app";
73 const char* const ROOT_HOME_PATH = "/opt/home/root";
74
75 WrtClient::WrtClient(int argc, char **argv) :
76     Application(argc, argv, "wrt-client", false),
77     DPL::TaskDecl<WrtClient>(this),
78     m_launched(false),
79     m_initializing(false),
80     m_initialized(false),
81     m_debugMode(false),
82     m_returnStatus(ReturnStatus::Succeeded),
83     m_widgetState(WidgetState::WidgetState_Stopped),
84     m_initialViewMode(VIEWMODE_TYPE_MAXIMIZED),
85     m_currentViewMode(VIEWMODE_TYPE_MAXIMIZED),
86     m_isWebkitFullscreen(false),
87     m_isFullscreenByPlatform(false),
88     m_submodeSupport(new ClientModule::SubmodeSupport())
89 {
90     Touch();
91     LogDebug("App Created");
92 }
93
94 WrtClient::~WrtClient()
95 {
96     LogDebug("App Finished");
97 }
98
99 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
100 {
101     return m_returnStatus;
102 }
103
104 void WrtClient::OnStop()
105 {
106     LogDebug("Stopping Dummy Client");
107 }
108
109 void WrtClient::OnCreate()
110 {
111     LogDebug("On Create");
112     ADD_PROFILING_POINT("OnCreate callback", "point");
113     ewk_init();
114 }
115
116 void WrtClient::OnResume()
117 {
118     if (m_widgetState != WidgetState_Suspended) {
119         LogWarning("Widget is not suspended, resuming was skipped");
120         return;
121     }
122     m_widget->Resume();
123     m_widgetState = WidgetState_Running;
124 }
125
126 void WrtClient::OnPause()
127 {
128     if (m_widgetState != WidgetState_Running) {
129         LogWarning("Widget is not running to be suspended");
130         return;
131     }
132     if (m_submodeSupport->isNeedTerminateOnSuspend()) {
133         LogDebug("Current mode cannot support suspend");
134         elm_exit();
135         return;
136     }
137     m_widget->Suspend();
138     m_widgetState = WidgetState_Suspended;
139 }
140
141 void WrtClient::OnReset(bundle *b)
142 {
143     LogDebug("OnReset");
144     // bundle argument is freed after OnReset() is returned
145     // So bundle duplication is needed
146     ApplicationDataSingleton::Instance().setBundle(bundle_dup(b));
147     ApplicationDataSingleton::Instance().setEncodedBundle(b);
148
149     if (true == m_initializing) {
150         LogDebug("can not handle reset event");
151         return;
152     }
153     if (true == m_launched) {
154         if (m_widgetState == WidgetState_Stopped) {
155             LogError("Widget is not running to be reset");
156             return;
157         }
158         m_widget->Reset();
159         m_widgetState = WidgetState_Running;
160     } else {
161         m_tizenId =
162             ClientModule::CommandLineParser::getTizenId(m_argc, m_argv);
163         if (m_tizenId.empty()) {
164             showHelpAndQuit();
165         } else {
166             setDebugMode(b);
167             setStep();
168         }
169     }
170
171     // low memory callback set
172     appcore_set_event_callback(
173             APPCORE_EVENT_LOW_MEMORY,
174             WrtClient::appcoreLowMemoryCallback,
175             this);
176 }
177
178 void WrtClient::OnTerminate()
179 {
180     LogDebug("Wrt Shutdown now");
181     shutdownStep();
182 }
183
184 void WrtClient::showHelpAndQuit()
185 {
186     printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
187            "launch widgets.\n"
188            "Mandatory arguments to long options are mandatory for short "
189            "options too.\n"
190            "  -h,    --help                                 show this help\n"
191            "  -l,    --launch                               "
192            "launch widget with given tizen ID\n"
193            "  -t,    --tizen                                "
194            "launch widget with given tizen ID\n"
195            "\n");
196
197     Quit();
198 }
199
200 void WrtClient::setStep()
201 {
202     LogDebug("setStep");
203
204     AddStep(&WrtClient::initStep);
205     AddStep(&WrtClient::launchStep);
206     AddStep(&WrtClient::shutdownStep);
207
208     m_initializing = true;
209
210     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
211 }
212
213 void WrtClient::setDebugMode(bundle* b)
214 {
215     m_debugMode = ClientModule::IDESupport::getDebugMode(b);
216     LogDebug("debug mode : " << m_debugMode);
217 }
218
219 void WrtClient::OnEventReceived(const NextStepEvent& /*event*/)
220 {
221     LogDebug("Executing next step");
222     NextStep();
223 }
224
225 void WrtClient::initStep()
226 {
227     LogDebug("");
228     if (WRT::CoreModuleSingleton::Instance().Init()) {
229         m_initialized = true;
230     } else {
231         m_returnStatus = ReturnStatus::Failed;
232         SwitchToStep(&WrtClient::shutdownStep);
233     }
234
235     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
236 }
237
238 void WrtClient::loadFinishCallback(Evas_Object* webview)
239 {
240     ADD_PROFILING_POINT("loadFinishCallback", "start");
241
242     // Splash screen
243     if (m_splashScreen && m_splashScreen->isShowing())
244     {
245         m_splashScreen->stopSplashScreenBuffered();
246     }
247
248     LogDebug("Post result of launch");
249
250     //w3c packaging test debug (message on 4>)
251     const char * makeScreen = getenv(W3C_DEBUG_ENV_VARIABLE);
252     if (makeScreen != NULL && strcmp(makeScreen, "1") == 0) {
253         FILE* doutput = fdopen(4, "w");
254         fprintf(doutput, "didFinishLoadForFrameCallback: ready\n");
255         fclose(doutput);
256     }
257
258     if (webview) {
259         LogDebug("Launch succesfull");
260
261         m_launched = true;
262         m_initializing = false;
263         setlinebuf(stdout);
264         ADD_PROFILING_POINT("loadFinishCallback", "stop");
265         printf("launched\n");
266         fflush(stdout);
267     } else {
268         printf("failed\n");
269
270         m_returnStatus = ReturnStatus::Failed;
271         //shutdownStep
272         DPL::Event::ControllerEventHandler<NextStepEvent>::
273             PostEvent(NextStepEvent());
274     }
275
276     if (m_debugMode) {
277         unsigned int portNum =
278             ewk_view_inspector_server_start(m_widget->GetCurrentWebview(), 0);
279         LogDebug("Port for inspector : " << portNum);
280         bool ret = ClientModule::IDESupport::sendReply(
281                        ApplicationDataSingleton::Instance().getBundle(),
282                        portNum);
283         if (!ret) {
284             LogWarning("Fail to send reply");
285         }
286     }
287
288     ApplicationDataSingleton::Instance().freeBundle();
289 }
290
291 void WrtClient::resetCallback(bool result)
292 {
293     if (!result) {
294         LogDebug("Fail to handle reset event");
295         // free bundle data
296         ApplicationDataSingleton::Instance().freeBundle();
297     }
298 }
299
300 void WrtClient::progressStartedCallback()
301 {
302     if (m_settingList->getProgressBarPresence() == ProgressBar_Enable ||
303         m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
304     {
305         m_windowData->signalEmit(Layer::MAIN_LAYOUT,
306                                  EDJE_SHOW_PROGRESS_SIGNAL,
307                                  "");
308         m_windowData->updateProgress(0);
309     }
310 }
311
312 void WrtClient::loadProgressCallback(Evas_Object* /*webview*/, double value)
313 {
314     if (m_settingList->getProgressBarPresence() == ProgressBar_Enable ||
315         m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
316     {
317         m_windowData->updateProgress(value);
318     }
319 }
320
321 void WrtClient::progressFinishCallback()
322 {
323     if (m_settingList->getProgressBarPresence() == ProgressBar_Enable ||
324         m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
325     {
326         m_windowData->signalEmit(Layer::MAIN_LAYOUT,
327                                  EDJE_HIDE_PROGRESS_SIGNAL,
328                                  "");
329     }
330 }
331
332 void WrtClient::webkitExitCallback()
333 {
334     LogDebug("window close called, terminating app");
335     SwitchToStep(&WrtClient::shutdownStep);
336     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
337         NextStepEvent());
338 }
339
340 void WrtClient::webCrashCallback()
341 {
342     LogError("webProcess crashed");
343     SwitchToStep(&WrtClient::shutdownStep);
344     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
345         NextStepEvent());
346 }
347
348 void WrtClient::enterFullscreenCallback(Evas_Object* /*obj*/,
349                                         bool isFullscreenByPlatform)
350 {
351     // enter fullscreen
352     m_windowData->toggleFullscreen(true);
353     m_currentViewMode = VIEWMODE_TYPE_FULLSCREEN;
354     m_isWebkitFullscreen = true;
355     if (isFullscreenByPlatform) {
356         m_isFullscreenByPlatform = true;
357     }
358 }
359
360 void WrtClient::exitFullscreenCallback(Evas_Object* /*obj*/)
361 {
362     // exit fullscreen
363     m_windowData->toggleFullscreen(false);
364     m_currentViewMode = m_initialViewMode;
365     m_isWebkitFullscreen = false;
366     m_isFullscreenByPlatform = false;
367 }
368
369 void WrtClient::launchStep()
370 {
371     ADD_PROFILING_POINT("launchStep", "start");
372     LogDebug("Launching widget ...");
373
374     ADD_PROFILING_POINT("getRunnableWidgetObject", "start");
375     m_widget = WRT::CoreModuleSingleton::Instance()
376             .getRunnableWidgetObject(m_tizenId);
377     ADD_PROFILING_POINT("getRunnableWidgetObject", "stop");
378
379     if (!m_widget) {
380         LogError("RunnableWidgetObject is NULL, stop launchStep");
381         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
382             NextStepEvent());
383         return;
384     }
385
386     if (m_widgetState == WidgetState_Running) {
387         LogWarning("Widget already running, stop launchStep");
388         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
389             NextStepEvent());
390         return;
391     }
392
393     if (m_widgetState == WidgetState_Authorizing) {
394         LogWarning("Widget already authorizing, stop launchStep");
395         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
396             NextStepEvent());
397         return;
398     }
399
400     m_dao.reset(new WrtDB::WidgetDAOReadOnly(DPL::FromASCIIString(m_tizenId)));
401     WrtDB::WidgetSettings widgetSettings;
402     m_dao->getWidgetSettings(widgetSettings);
403     m_settingList.reset(new WidgetSettingList(widgetSettings));
404     m_submodeSupport->initialize(DPL::FromASCIIString(m_tizenId));
405
406     DPL::Optional<DPL::String> defloc = m_dao->getDefaultlocale();
407     if (!defloc.IsNull()) {
408         LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
409             *defloc);
410     }
411
412     setInitialViewMode();
413     PrepareExternalStorageSingleton::Instance().Initialize(m_dao->getTizenPkgId());
414
415     /* remove language change callback */
416     /*
417     LocalizationSetting::SetLanguageChangedCallback(
418             languageChangedCallback, this);
419     */
420
421     ADD_PROFILING_POINT("CreateWindow", "start");
422     if (s_preparedWindowData == NULL) {
423         m_windowData.reset(new WindowData(static_cast<unsigned long>(getpid()), true));
424     } else {
425         m_windowData.reset(s_preparedWindowData);
426         s_preparedWindowData = NULL;
427     }
428     ADD_PROFILING_POINT("CreateWindow", "stop");
429     if (!m_windowData->initScreenReaderSupport(
430             m_settingList->getAccessibility() == Accessibility_Enable))
431     {
432         LogWarning("Fail to set screen reader support set");
433     }
434
435     // rotate window to initial value
436     setWindowInitialOrientation();
437     setCtxpopupItem();
438
439     WRT::UserDelegatesPtr cbs(new WRT::UserDelegates);
440
441     ADD_PROFILING_POINT("Create splash screen", "start");
442     DPL::OptionalString splashImgSrc = m_dao->getSplashImgSrc();
443     if (!splashImgSrc.IsNull())
444     {
445         m_splashScreen.reset(
446             new SplashScreenSupport(
447                 m_windowData->getEvasObject(Layer::WINDOW),
448                 (DPL::ToUTF8String(*splashImgSrc)).c_str(),
449                 m_currentViewMode != VIEWMODE_TYPE_FULLSCREEN,
450                 m_settingList->getRotationValue() == Screen_Landscape));
451         m_splashScreen->startSplashScreen();
452     }
453     ADD_PROFILING_POINT("Create splash screen", "stop");
454
455     DPL::OptionalString startUrl = W3CFileLocalization::getStartFile(m_dao);
456     if (!m_widget->PrepareView(
457             DPL::ToUTF8String(*startUrl),
458             m_windowData->getEvasObject(Layer::WINDOW),
459             s_preparedEwkContext))
460     {
461         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
462             NextStepEvent());
463         return;
464     }
465     // send rotate information to ewk
466     setEwkInitialOrientation();
467
468     //you can't show window with splash screen before PrepareView
469     //ewk_view_add_with_context() in viewLogic breaks window
470     m_windowData->init();
471     m_windowData->postInit();
472
473     // sub-mode support
474     if (m_submodeSupport->isInlineMode()) {
475         if (m_submodeSupport->transientWindow(
476                 elm_win_xwindow_get(
477                     m_windowData->getEvasObject(Layer::WINDOW))))
478         {
479             LogDebug("Success to set submode");
480         } else {
481             LogWarning("Fail to set submode");
482         }
483     }
484     m_windowData->smartCallbackAdd(Layer::FOCUS,
485                                    "focused",
486                                    focusedCallback,
487                                    this);
488     m_windowData->smartCallbackAdd(Layer::FOCUS,
489                                    "unfocused",
490                                    unfocusedCallback,
491                                    this);
492
493     WrtDB::WidgetLocalizedInfo localizedInfo =
494         W3CFileLocalization::getLocalizedInfo(m_dao);
495     std::string name = "";
496     if (!(localizedInfo.name.IsNull())) {
497         name = DPL::ToUTF8String(*(localizedInfo.name));
498     }
499     elm_win_title_set(m_windowData->getEvasObject(Layer::WINDOW),
500                       name.c_str());
501
502     // window show
503     evas_object_show(m_windowData->getEvasObject(Layer::WINDOW));
504
505     initializeWindowModes();
506
507     m_widgetState = WidgetState_Authorizing;
508     if (!m_widget->CheckBeforeLaunch()) {
509         LogError("CheckBeforeLaunch failed, stop launchStep");
510         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
511             NextStepEvent());
512         return;
513     }
514     LogDebug("Widget launch accepted. Entering running state");
515     m_widgetState = WidgetState_Running;
516
517     cbs->progressStarted = DPL::MakeDelegate(this, &WrtClient::progressStartedCallback);
518     cbs->progress = DPL::MakeDelegate(this, &WrtClient::loadProgressCallback);
519     cbs->progressFinish = DPL::MakeDelegate(this, &WrtClient::progressFinishCallback);
520     cbs->loadFinish = DPL::MakeDelegate(this, &WrtClient::loadFinishCallback);
521     cbs->reset = DPL::MakeDelegate(this, &WrtClient::resetCallback);
522     cbs->bufferSet = DPL::MakeDelegate(this, &WrtClient::setLayout);
523     cbs->bufferUnset = DPL::MakeDelegate(this, &WrtClient::unsetLayout);
524     cbs->webkitExit = DPL::MakeDelegate(this, &WrtClient::webkitExitCallback);
525     cbs->webCrash = DPL::MakeDelegate(this, &WrtClient::webCrashCallback);
526     cbs->enterFullscreen = DPL::MakeDelegate(this, &WrtClient::enterFullscreenCallback);
527     cbs->exitFullscreen = DPL::MakeDelegate(this, &WrtClient::exitFullscreenCallback);
528     cbs->setOrientation = DPL::MakeDelegate(this, &WrtClient::setWindowOrientation);
529     cbs->hwkey = DPL::MakeDelegate(this, &WrtClient::hwkeyCallback);
530
531     m_widget->SetUserDelegates(cbs);
532     m_widget->Show();
533
534     ADD_PROFILING_POINT("launchStep", "stop");
535 }
536
537 void WrtClient::initializeWindowModes()
538 {
539     Assert(m_windowData);
540     bool backbutton =
541         (m_settingList->getBackButtonPresence() == BackButton_Enable ||
542         m_currentViewMode == VIEWMODE_TYPE_WINDOWED);
543     m_windowData->setViewMode(m_currentViewMode == VIEWMODE_TYPE_FULLSCREEN,
544                               backbutton);
545 }
546
547 Eina_Bool WrtClient::naviframeBackButtonCallback(void* data,
548                                                  Elm_Object_Item* /*it*/)
549 {
550     LogDebug("BackButtonCallback");
551     Assert(data);
552
553     WrtClient* This = static_cast<WrtClient*>(data);
554     This->m_widget->Backward();
555     return EINA_FALSE;
556 }
557
558 int WrtClient::appcoreLowMemoryCallback(void* /*data*/)
559 {
560     LogDebug("appcoreLowMemoryCallback");
561     //WrtClient* This = static_cast<WrtClient*>(data);
562
563     // TODO call RunnableWidgetObject API regarding low memory
564     // The API should be implemented
565
566     // temporary solution because we have no way to get ewk_context from runnable object.
567     if (s_preparedEwkContext)
568     {
569         ewk_context_cache_clear(s_preparedEwkContext);
570         ewk_context_notify_low_memory(s_preparedEwkContext);
571     }
572
573     return 0;
574 }
575
576 void WrtClient::setInitialViewMode(void)
577 {
578     Assert(m_dao);
579     WrtDB::WindowModeList windowModes = m_dao->getWindowModes();
580     FOREACH(it, windowModes) {
581         std::string viewMode = DPL::ToUTF8String(*it);
582         switch(viewMode[0]) {
583             case 'f':
584                 if (viewMode == VIEWMODE_TYPE_FULLSCREEN) {
585                     m_initialViewMode = viewMode;
586                     m_currentViewMode = m_initialViewMode;
587                     break;
588                 }
589                 break;
590             case 'm':
591                 if (viewMode == VIEWMODE_TYPE_MAXIMIZED) {
592                     m_initialViewMode = viewMode;
593                     m_currentViewMode = m_initialViewMode;
594                     break;
595                 }
596                 break;
597             case 'w':
598                 if (viewMode == VIEWMODE_TYPE_WINDOWED) {
599                     m_initialViewMode = viewMode;
600                     m_currentViewMode = m_initialViewMode;
601                     break;
602                 }
603                 break;
604             default:
605                 break;
606         }
607     }
608 }
609
610 void WrtClient::setWindowInitialOrientation(void)
611 {
612     Assert(m_windowData);
613     Assert(m_dao);
614
615     WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue();
616     if (rotationValue == Screen_Portrait) {
617         setWindowOrientation(OrientationAngle::Window::Portrait::PRIMARY);
618     } else if (rotationValue == Screen_Landscape) {
619         setWindowOrientation(OrientationAngle::Window::Landscape::PRIMARY);
620     } else if (rotationValue == Screen_AutoRotation) {
621         if (!AutoRotationSupport::setAutoRotation(
622                 m_windowData->getEvasObject(Layer::WINDOW),
623                 autoRotationCallback,
624                 this))
625         {
626             LogError("Fail to set auto rotation");
627         }
628     } else {
629         setWindowOrientation(OrientationAngle::Window::Portrait::PRIMARY);
630     }
631 }
632
633 void WrtClient::setWindowOrientation(int angle)
634 {
635     Assert(m_windowData);
636     m_windowData->setOrientation(angle);
637 }
638
639 void WrtClient::unsetWindowOrientation(void)
640 {
641     Assert(m_windowData);
642     Assert(m_dao);
643
644     WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue();
645     if (rotationValue == Screen_AutoRotation) {
646         AutoRotationSupport::unsetAutoRotation(
647             m_windowData->getEvasObject(Layer::WINDOW),
648             autoRotationCallback);
649     }
650 }
651
652 void WrtClient::setEwkInitialOrientation(void)
653 {
654     Assert(m_widget);
655     Assert(m_dao);
656
657     WidgetSettingScreenLock rotationValue = m_settingList->getRotationValue();
658     if (rotationValue == Screen_Portrait) {
659         ewk_view_orientation_send(
660             m_widget->GetCurrentWebview(),
661              OrientationAngle::W3C::Portrait::PRIMARY);
662     } else if (rotationValue == Screen_Landscape) {
663         ewk_view_orientation_send(
664             m_widget->GetCurrentWebview(),
665             OrientationAngle::W3C::Landscape::PRIMARY);
666     } else if (rotationValue == Screen_AutoRotation) {
667          ewk_view_orientation_send(
668             m_widget->GetCurrentWebview(),
669             OrientationAngle::W3C::Portrait::PRIMARY);
670     } else {
671         ewk_view_orientation_send(
672             m_widget->GetCurrentWebview(),
673             OrientationAngle::W3C::Portrait::PRIMARY);
674     }
675 }
676
677 void WrtClient::ExitCallback(void* data,
678                                    Evas_Object * /*obj*/,
679                                    void * /*event_info*/)
680 {
681     LogInfo("ExitCallback");
682     Assert(data);
683
684     WrtClient* This = static_cast<WrtClient*>(data);
685
686     This->OnTerminate();
687 }
688
689 void WrtClient::setCtxpopupItem(void)
690 {
691     WindowData::CtxpopupItemDataList data;
692
693     // 1. share
694     WindowData::CtxpopupCallbackType shareCallback =
695         DPL::MakeDelegate(this, &WrtClient::ctxpopupShare);
696     WindowData::CtxpopupItemData shareData("Share",
697                                            std::string(),
698                                            shareCallback);
699
700     // 2. reload
701     WindowData::CtxpopupCallbackType reloadCallback =
702         DPL::MakeDelegate(this, &WrtClient::ctxpopupReload);
703     WindowData::CtxpopupItemData reloadData("Reload",
704                                             std::string(),
705                                             reloadCallback);
706
707     // 3. Open in browser
708     WindowData::CtxpopupCallbackType launchBrowserCallback =
709         DPL::MakeDelegate(this, &WrtClient::ctxpopupLaunchBrowser);
710     WindowData::CtxpopupItemData launchBrowserData("Open in browser",
711                                                    std::string(),
712                                                    launchBrowserCallback);
713     data.push_back(shareData);
714     data.push_back(reloadData);
715     data.push_back(launchBrowserData);
716     m_windowData->setCtxpopupItemData(data);
717 }
718
719 void WrtClient::ctxpopupShare(void)
720 {
721     LogDebug("share");
722     const char* url = ewk_view_url_get(m_widget->GetCurrentWebview());
723     if (!url) {
724         LogError("url is empty");
725         return;
726     }
727     if (ClientModule::ServiceSupport::launchShareService(
728             elm_win_xwindow_get(m_windowData->getEvasObject(Layer::WINDOW)),
729             url))
730     {
731         LogDebug("success");
732     } else {
733         LogDebug("fail");
734     }
735     evas_object_smart_callback_add(m_windowData->m_win,
736             "delete,request",
737             &WrtClient::ExitCallback,
738             this);
739 }
740
741 void WrtClient::ctxpopupReload(void)
742 {
743     LogDebug("reload");
744     ewk_view_reload(m_widget->GetCurrentWebview());
745 }
746
747 void WrtClient::ctxpopupLaunchBrowser(void)
748 {
749     LogDebug("launchBrowser");
750     const char* url = ewk_view_url_get(m_widget->GetCurrentWebview());
751     if (!url) {
752         LogError("url is empty");
753         return;
754     }
755     if (ClientModule::ServiceSupport::launchViewService(
756             elm_win_xwindow_get(m_windowData->getEvasObject(Layer::WINDOW)),
757             url))
758     {
759         LogDebug("success");
760     } else {
761         LogDebug("fail");
762     }
763 }
764
765 void WrtClient::hwkeyCallback(const std::string& key)
766 {
767     if (m_settingList->getBackButtonPresence() == BackButton_Enable
768         || m_currentViewMode == VIEWMODE_TYPE_WINDOWED)
769     {
770         // windowed UX - hosted application
771         if (key == KeyName::BACK) {
772             if (m_isWebkitFullscreen) {
773                 ewk_view_fullscreen_exit(m_widget->GetCurrentWebview());
774             } else {
775                 m_widget->Backward();
776             }
777         } else if (key == KeyName::MENU) {
778             // UX isn't confirmed
779             // m_windowData->showCtxpopup();
780         }
781     } else {
782         // packaged application
783         if (key == KeyName::BACK) {
784             if (m_isFullscreenByPlatform) {
785                 ewk_view_fullscreen_exit(m_widget->GetCurrentWebview());
786             }
787         }
788     }
789 }
790
791 void WrtClient::setLayout(Evas_Object* webview)
792 {
793     LogDebug("add new webkit buffer to window");
794     Assert(webview);
795     m_windowData->setWebview(webview);
796     evas_object_show(webview);
797     evas_object_show(m_windowData->getEvasObject(Layer::WINDOW));
798 }
799
800 void WrtClient::unsetLayout(Evas_Object* webview)
801 {
802     LogDebug("remove current webkit buffer from window");
803     Assert(webview);
804     evas_object_hide(webview);
805     m_windowData->unsetWebview();
806 }
807
808 void WrtClient::shutdownStep()
809 {
810     LogDebug("Closing Wrt connection ...");
811
812     if (m_widget && m_widgetState) {
813         m_widgetState = WidgetState_Stopped;
814         m_widget->Hide();
815         // AutoRotation, focusCallback use m_widget pointer internally.
816         // It must be unset before m_widget is released.
817         m_submodeSupport->deinitialize();
818         unsetWindowOrientation();
819         m_windowData->smartCallbackDel(Layer::FOCUS,
820                                        "focused",
821                                        focusedCallback);
822         m_windowData->smartCallbackDel(Layer::FOCUS,
823                                        "unfocused",
824                                        unfocusedCallback);
825         m_widget.reset();
826         ewk_context_delete(s_preparedEwkContext);
827         PrepareExternalStorageSingleton::Instance().Deinitialize();
828         WRT::CoreModuleSingleton::Instance().Terminate();
829     }
830     if (m_initialized) {
831         m_initialized = false;
832     }
833     m_windowData.reset();
834     Quit();
835 }
836
837 void WrtClient::autoRotationCallback(void* data, Evas_Object* obj, void* /*event*/)
838 {
839     LogDebug("entered");
840
841     Assert(data);
842     Assert(obj);
843
844     WrtClient* This = static_cast<WrtClient*>(data);
845     This->autoRotationSetOrientation(obj);
846 }
847
848 void WrtClient::focusedCallback(void* data,
849                                 Evas_Object* /*obj*/,
850                                 void* /*eventInfo*/)
851 {
852     LogDebug("entered");
853     Assert(data);
854     WrtClient* This = static_cast<WrtClient*>(data);
855     elm_object_focus_set(This->m_widget->GetCurrentWebview(), EINA_TRUE);
856 }
857
858 void WrtClient::unfocusedCallback(void* data,
859                                 Evas_Object* /*obj*/,
860                                 void* /*eventInfo*/)
861 {
862     LogDebug("entered");
863     Assert(data);
864     WrtClient* This = static_cast<WrtClient*>(data);
865     elm_object_focus_set(This->m_widget->GetCurrentWebview(), EINA_FALSE);
866 }
867
868 void WrtClient::autoRotationSetOrientation(Evas_Object* obj)
869 {
870     LogDebug("entered");
871     Assert(obj);
872
873     AutoRotationSupport::setOrientation(obj, m_widget->GetCurrentWebview(),
874                                 (m_splashScreen) ? m_splashScreen.get(): NULL);
875 }
876
877 int WrtClient::languageChangedCallback(void *data)
878 {
879     LogDebug("Language Changed");
880     if (!data) {
881         return 0;
882     }
883     WrtClient* wrtClient = static_cast<WrtClient*>(data);
884     if (!(wrtClient->m_dao)) {
885         return 0;
886     }
887
888     // reset function fetches system locales and recreates language tags
889     LanguageTagsProviderSingleton::Instance().resetLanguageTags();
890     // widget default locales are added to language tags below
891     DPL::OptionalString defloc = wrtClient->m_dao->getDefaultlocale();
892     if (!defloc.IsNull()) {
893         LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
894             *defloc);
895     }
896
897     if (wrtClient->m_launched &&
898         wrtClient->m_widgetState != WidgetState_Stopped)
899     {
900         wrtClient->m_widget->ReloadStartPage();
901     }
902     return 0;
903 }
904
905 void WrtClient::Quit()
906 {
907     ewk_shutdown();
908     DPL::Application::Quit();
909 }
910
911 static Eina_Bool proces_pool_fd_handler(void* /*data*/, Ecore_Fd_Handler *handler)
912 {
913     int fd = ecore_main_fd_handler_fd_get(handler);
914
915     if (fd == -1)
916     {
917         LogDebug("ECORE_FD_GET");
918         exit(-1);
919     }
920
921     if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR))
922     {
923         LogDebug("ECORE_FD_ERROR");
924         close(fd);
925         exit(-1);
926     }
927
928     if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ))
929     {
930         LogDebug("ECORE_FD_READ");
931         {
932             app_pkt_t* pkt = (app_pkt_t*) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
933             memset(pkt, 0, AUL_SOCK_MAXBUFF);
934
935             int recv_ret = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0);
936             close(fd);
937
938             if (recv_ret == -1)
939             {
940                 LogDebug("recv error!");
941                 free(pkt);
942                 exit(-1);
943             }
944
945             LogDebug("recv_ret : " << recv_ret << ", pkt->len : " << pkt->len);
946             ecore_main_fd_handler_del(handler);
947             process_pool_launchpad_main_loop(pkt, app_argv[0], &app_argc, &app_argv);
948             free(pkt);
949         }
950         ecore_main_loop_quit();
951     }
952
953     return ECORE_CALLBACK_CANCEL;
954 }
955
956 static void vconf_changed_handler(keynode_t* /*key*/, void* /*data*/)
957 {
958     LogDebug("VCONFKEY_LANGSET vconf-key was changed!");
959
960     // When system language is changed, the candidate process will be created again.
961     exit(-1);
962 }
963
964 void set_env()
965 {
966 #ifndef TIZEN_PUBLIC
967     setenv("COREGL_FASTPATH", "1", 1);
968 #endif
969     setenv("CAIRO_GL_COMPOSITOR", "msaa", 1);
970     setenv("CAIRO_GL_LAZY_FLUSHING", "yes", 1);
971     setenv("ELM_IMAGE_CACHE", "0", 1);
972 }
973
974 int main(int argc,
975          char *argv[])
976 {
977     // process pool - store arg's value
978     app_argc = argc;
979     app_argv = argv;
980
981 #ifndef X11
982     // Mesa does a bad job detecting the correct EGL
983     // platform to use, and ends up assuming that the
984     // wrt-client is using X
985     setenv("EGL_PLATFORM", "wayland", 1);
986 #endif
987
988     UNHANDLED_EXCEPTION_HANDLER_BEGIN
989     {
990         ADD_PROFILING_POINT("main-entered", "point");
991
992         // Set log tagging
993         DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
994
995         // Set environment variables
996         set_env();
997
998         if (argc > 1 && argv[1] != NULL && !strcmp(argv[1], "-d"))
999         {
1000             LogDebug("Entered dummy process mode");
1001             sprintf(argv[0], "%s                                              ",
1002                     DUMMY_PROCESS_PATH);
1003
1004             // Set 'root' home directory
1005             setenv(HOME, ROOT_HOME_PATH, 1);
1006
1007             LogDebug("Prepare ewk_context");
1008             appcore_set_i18n("wrt-client", NULL);
1009             ewk_set_arguments(argc, argv);
1010             setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
1011             s_preparedEwkContext = ewk_context_new_with_injected_bundle_path(BUNDLE_PATH);
1012
1013             if (s_preparedEwkContext == NULL)
1014             {
1015                 LogDebug("Creating webkit context was failed!");
1016                 exit(-1);
1017             }
1018
1019             int client_fd = __connect_process_pool_server();
1020
1021             if (client_fd == -1)
1022             {
1023                 LogDebug("Connecting process_pool_server was failed!");
1024                 exit(-1);
1025             }
1026
1027             // register language changed callback
1028             vconf_notify_key_changed(VCONFKEY_LANGSET, vconf_changed_handler, NULL);
1029
1030             LogDebug("Prepare window_data");
1031             // Temporarily change HOME path to app
1032             // This change is needed for getting elementary profile
1033             // /opt/home/app/.elementary/config/mobile/base.cfg
1034             const char* backupEnv = getenv(HOME);
1035             setenv(HOME, APP_HOME_PATH, 1);
1036             LogDebug("elm_init()");
1037             elm_init(argc, argv);
1038             setenv(HOME, backupEnv, 1);
1039
1040             LogDebug("WindowData()");
1041             s_preparedWindowData = new WindowData(static_cast<unsigned long>(getpid()));
1042
1043             Ecore_Fd_Handler* fd_handler = ecore_main_fd_handler_add(client_fd,
1044                                            (Ecore_Fd_Handler_Flags)(ECORE_FD_READ|ECORE_FD_ERROR),
1045                                            proces_pool_fd_handler, NULL, NULL, NULL);
1046
1047             if (fd_handler == NULL)
1048             {
1049                 LogDebug("fd_handler is NULL");
1050                 exit(-1);
1051             }
1052
1053             setpriority(PRIO_PROCESS, 0, 0);
1054
1055             LogDebug("ecore_main_loop_begin()");
1056             ecore_main_loop_begin();
1057             LogDebug("ecore_main_loop_begin()_end");
1058
1059             // deregister language changed callback
1060             vconf_ignore_key_changed(VCONFKEY_LANGSET, vconf_changed_handler);
1061
1062             std::string tizenId =
1063                 ClientModule::CommandLineParser::getTizenId(argc, argv);
1064             ewk_context_message_post_to_injected_bundle(
1065                 s_preparedEwkContext,
1066                 MESSAGE_NAME_INITIALIZE,
1067                 tizenId.c_str());
1068
1069         }
1070         else
1071         {
1072             // This code is to fork a web process without exec.
1073             std::string tizenId =
1074                 ClientModule::CommandLineParser::getTizenId(argc, argv);
1075
1076             if (!tizenId.empty()) {
1077                 if (UID_ROOT == getuid()) {
1078                     // Drop root permission
1079                     // Only launch web application by console command case has root permission
1080                     if (!ClientModule::SecuritySupport::setAppPrivilege(tizenId)) {
1081                         LogError("Fail to set app privilege : [" << tizenId << "]");
1082                         exit(-1);
1083                     }
1084                 }
1085
1086                 LogDebug("Launching by fork mode");
1087                 // Language env setup
1088                 appcore_set_i18n("wrt-client", NULL);
1089                 ewk_set_arguments(argc, argv);
1090                 setenv("WRT_LAUNCHING_PERFORMANCE", "1", 1);
1091                 s_preparedEwkContext = ewk_context_new_with_injected_bundle_path(
1092                         BUNDLE_PATH);
1093
1094                 if (s_preparedEwkContext == NULL)
1095                 {
1096                     LogDebug("Creating webkit context was failed!");
1097                     Wrt::Popup::PopupInvoker().showInfo("Error", "Creating webkit context was failed.", "OK");
1098                     exit(-1);
1099                 }
1100
1101                 // plugin init
1102                 ewk_context_message_post_to_injected_bundle(
1103                     s_preparedEwkContext,
1104                     MESSAGE_NAME_INITIALIZE,
1105                     tizenId.c_str());
1106             }
1107         }
1108
1109         // Output on stdout will be flushed after every newline character,
1110         // even if it is redirected to a pipe. This is useful for running
1111         // from a script and parsing output.
1112         // (Standard behavior of stdlib is to use full buffering when
1113         // redirected to a pipe, which means even after an end of line
1114         // the output may not be flushed).
1115         setlinebuf(stdout);
1116
1117         WrtClient app(app_argc, app_argv);
1118
1119         ADD_PROFILING_POINT("Before appExec", "point");
1120         int ret = app.Exec();
1121         LogDebug("App returned: " << ret);
1122         ret = app.getReturnStatus();
1123         LogDebug("WrtClient returned: " << ret);
1124         return ret;
1125     }
1126     UNHANDLED_EXCEPTION_HANDLER_END
1127 }