Update wrt_0.8.88
[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 <cstdlib>
18 #include <cstdio>
19 #include <string>
20 #include <dpl/log/log.h>
21 #include <dpl/optional_typedefs.h>
22 #include <common/application_data.h>
23 #include <core_module.h>
24 #include <global_logic.h>
25 #include <widget_model.h>
26 #include <widget_localize_model.h>
27 #include <localization_setting.h>
28 #include <widget_deserialize_model.h>
29 #include <launch_user_data.h>
30 #include <EWebKit2.h>
31
32 //W3C PACKAGING enviroment variable name
33 #define W3C_DEBUG_ENV_VARIABLE "DEBUG_LOAD_FINISH"
34
35 WrtClient::WrtClient(int argc, char **argv) :
36     Application(argc, argv, "wrt-client", false),
37     DPL::TaskDecl<WrtClient>(this),
38     m_handle(-1),
39     m_launched(false),
40     m_initializing(false),
41     m_initialized(false),
42     m_sdkLauncherPid(0),
43     m_debugMode(false),
44     m_debuggerPort(0),
45     m_returnStatus(ReturnStatus::Succeeded),
46     m_widgetState(WidgetState::WidgetState_Stopped)
47 {
48     Touch();
49     LogDebug("App Created");
50 }
51
52 WrtClient::~WrtClient()
53 {
54     LogDebug("App Finished");
55 }
56
57 WrtClient::ReturnStatus::Type WrtClient::getReturnStatus() const
58 {
59     return m_returnStatus;
60 }
61
62 void WrtClient::OnStop()
63 {
64     LogInfo("Stopping Dummy Client");
65 }
66
67
68 void WrtClient::OnCreate()
69 {
70     LogInfo("On Create");
71 }
72
73
74 void WrtClient::OnResume()
75 {
76     if (m_widgetState != WidgetState_Suspended) {
77         LogWarning("Widget is not suspended, resuming was skipped");
78         return;
79     }
80     m_widget->Resume();
81     m_widgetState = WidgetState_Running;
82 }
83
84
85 void WrtClient::OnPause()
86 {
87     if (m_widgetState != WidgetState_Running) {
88         LogWarning("Widget is not running to be suspended");
89         return;
90     }
91     m_widget->Suspend();
92     m_widgetState = WidgetState_Suspended;
93 }
94
95 void WrtClient::OnReset(bundle *b)
96 {
97     LogDebug("OnReset");
98     // bundle argument is freed after OnReset() is returned
99     // So bundle duplication is needed
100     ApplicationDataSingleton::Instance().setBundle(bundle_dup(b));
101
102     if (true == m_initializing) {
103         LogDebug("can not handle reset event");
104         return;
105     }
106     if (true == m_launched) {
107         if (m_widgetState == WidgetState_Stopped) {
108             LogError("Widget is not running to be reset");
109             return;
110         }
111         m_widget->Reset();
112         m_widgetState = WidgetState_Running;
113     } else {
114         if (true == checkArgument())
115         {
116             setStep();
117         }
118         else
119         {
120             showHelpAndQuit();
121         }
122     }
123 }
124
125 void WrtClient::OnTerminate()
126 {
127     LogDebug("Wrt Shutdown now");
128     shutdownStep();
129 }
130
131 void WrtClient::showHelpAndQuit()
132 {
133     printf("Usage: wrt-client [OPTION]... [WIDGET: ID]...\n"
134            "launch widgets.\n"
135            "Mandatory arguments to long options are mandatory for short "
136            "options too.\n"
137            "  -h,    --help                                 show this help\n"
138            "  -l,    --launch                               "
139            "launch widget with given ID\n"
140            "\n");
141
142     Quit();
143 }
144
145 bool WrtClient::checkArgument()
146 {
147     LogInfo("checkArgument");
148
149     std::string arg = m_argv[0];
150
151     if (arg.empty()) {
152         return false;
153     }
154
155     if (arg.find("wrt-client") != std::string::npos)
156     {
157         if (m_argc <= 1) {
158             return false;
159         }
160
161         arg = m_argv[1];
162
163         if (arg == "-h" || arg == "--help") {
164             // Just show help
165             return false;
166         } else if (arg == "-l" || arg == "--launch") {
167             if (m_argc != 3) {
168                 return false;
169             }
170             m_handle = atoi(m_argv[2]);
171         } else {
172             return false;
173         }
174     } else {
175         size_t pos = arg.find_last_of('/');
176
177         if (pos != std::string::npos) {
178             arg = arg.erase(0, pos + 1);
179         }
180
181         // Launch widget based on application basename
182         if (sscanf(arg.c_str(), "%i", &m_handle) != 1) {
183             printf("failed: invalid widget handle\n");
184             return false;
185         }
186
187         LogDebug("Widget Id: " << m_handle << " (" << arg << ")");
188     }
189
190     return true;
191 }
192
193 void WrtClient::setStep()
194 {
195     LogInfo("setStep");
196
197     AddStep(&WrtClient::initStep);
198
199     setSdkLauncherDebugData();
200
201     AddStep(&WrtClient::launchStep);
202     AddStep(&WrtClient::shutdownStep);
203
204     m_initializing = true;
205
206     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(NextStepEvent());
207 }
208
209 void WrtClient::setSdkLauncherDebugData()
210 {
211     LogDebug("setSdkLauncherDebugData");
212
213     /* check bundle from sdk launcher */
214     bundle *bundleFromSdkLauncher;
215     bundleFromSdkLauncher = bundle_import_from_argv(m_argc, m_argv);
216     const char *bundle_debug = bundle_get_val(bundleFromSdkLauncher, "debug");
217     const char *bundle_pid = bundle_get_val(bundleFromSdkLauncher, "pid");
218     if (bundle_debug != NULL && bundle_pid != NULL) {
219         if (strcmp(bundle_debug, "true") == 0) {
220             m_debugMode = true;
221             m_sdkLauncherPid = atoi(bundle_pid);
222         } else {
223             m_debugMode = false;
224         }
225     }
226 }
227
228 bool WrtClient::checkDebugMode(WidgetModel* model, SDKDebugData* debugData)
229 {
230     LogError("Checking for debug mode");
231     Assert(model && "Passed widget model is NULL!");
232
233     bool debugMode = debugData->debugMode;
234
235     LogInfo("[DEBUG_MODE] Widget is launched in " <<
236             (debugMode ? "DEBUG" : "RETAIL") <<
237             " mode.");
238
239     if (debugMode == true) {
240         // In WAC widget, only test widgets can use web inspector.
241         // In TIZEN widget,
242         // every launched widgets as debug mode can use it.
243         if (model->Type.Get().appType ==
244             WrtDB::APP_TYPE_WAC20)
245         {
246             bool developerMode =
247                 GlobalLogicSingleton::Instance().GetGlobalModel()
248                 ->DeveloperMode.Get();
249             //This code will be activated
250             //after WAC test certificate is used by SDK
251             //bool isTestWidget = view->m_widgetModel->IsTestWidget.Get();
252             //if(!isTestWidget)
253             //{
254             //    LogInfo("This is not WAC Test Widget");
255             //    break;
256             //}
257             if (!developerMode) {
258                 LogInfo("This is not WAC Developer Mode");
259                 debugMode = false;
260             }
261         }
262     }
263     return debugMode;
264 }
265
266 void WrtClient::OnEventReceived(const NextStepEvent& /*event*/)
267 {
268     LogDebug("Executing next step");
269     NextStep();
270 }
271
272 void WrtClient::initStep()
273 {
274     LogDebug("");
275     if (WRT::CoreModuleSingleton::Instance().Init()) {
276         m_initialized = true;
277     } else {
278         m_returnStatus = ReturnStatus::Failed;
279         SwitchToStep(&WrtClient::shutdownStep);
280     }
281     DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
282             NextStepEvent());
283 }
284
285 void WrtClient::localizeWidgetModel() {
286     Assert(!!m_widget);
287     WRT::WidgetModelPtr model = m_widget->GetModel();
288     Assert(!!model);
289     Domain::localizeWidgetModel(model);
290     model->RunningName.Set(model->Name.Get());
291     model->RunningIcon.Set(model->Icon.Get());
292     model->RunningStartURL.Set(model->StartURL.Get());
293     model->RunningShortName.Set(model->ShortName.Get());
294     model->RunningDescription.Set(model->Description.Get());
295     model->RunningLicense.Set(model->License.Get());
296     model->RunningLicenseHref.Set(model->LicenseHref.Get());
297     model->RunningStartFileInfo.Set(
298         model->StartFileInfo.Get());
299 }
300
301 bool WrtClient::checkWACTestCertififedWidget()
302 {
303     // WAC Waikiki Beta Release Core Specification: Widget Runtime
304     // 10 Dec 2010
305     //
306     // WR-4710 The WRT MUST enable debug functions only for WAC test widgets
307     // i.e. the functions must not be usable for normal WAC widgets, even when
308     // a WAC test widget is executing.
309     ADD_PROFILING_POINT("DeveloperModeCheck", "start");
310     Assert(!!m_widget);
311     WRT::WidgetModelPtr model = m_widget->GetModel();
312     Assert(!!model);
313     // WAC test widget
314     // A widget signed with a WAC-issued test certificate as described in
315     // Developer Mode.
316
317     bool developerWidget = model->IsTestWidget.Get();
318     bool developerMode =
319         GlobalLogicSingleton::Instance().GetGlobalModel()->DeveloperMode.Get();
320
321     LogDebug("Is WAC test widget: " << developerWidget);
322     LogDebug("Is developer Mode: " << developerMode);
323
324     if (developerWidget) {
325         if(!developerMode)
326         {
327             LogError("WAC test certified developer widget is needed for " <<
328                     "developer mode");
329             return false;
330         }else{
331             //TODO: WR-4660 (show popup about developer widget
332             //      during launch
333             LogInfo("POPUP: THIS IS TEST WIDGET!");
334         }
335     }
336     ADD_PROFILING_POINT("DeveloperModeCheck", "stop");
337     return true;
338 }
339
340 void WrtClient::loadFinishCallback(bool success, void* data)
341 {
342     WrtClient* wrtClient = static_cast<WrtClient*>(data);
343     SDKDebugData* debug = new SDKDebugData;
344     debug->debugMode = wrtClient->m_debugMode;
345     debug->pid = new unsigned long(getpid());
346
347     LogInfo("Post result of launch");
348
349     // Start inspector server, if current mode is debugger mode.
350     // In the WK2 case, ewk_view_inspector_server_start should
351     // be called after WebProcess is created.
352     if (wrtClient->checkDebugMode(
353                 wrtClient->m_widget->GetModel().get(), debug))
354     {
355         debug->portnum =
356             ewk_view_inspector_server_start(
357                     wrtClient->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     {
372         FILE* doutput = fdopen(4, "w");
373         fprintf(doutput,"didFinishLoadForFrameCallback: ready\n");
374         fclose(doutput);
375     }
376
377     if (success) {
378         LogDebug("Launch succesfull");
379
380         wrtClient->m_launched = true;
381         wrtClient->m_initializing = false;
382         setlinebuf(stdout);
383         printf("launched\n");
384         fflush(stdout);
385     } else {
386         printf("failed\n");
387
388         wrtClient->m_returnStatus = ReturnStatus::Failed;
389         //shutdownStep
390         wrtClient->DPL::Event::ControllerEventHandler<NextStepEvent>::
391                 PostEvent(NextStepEvent());
392     }
393
394     if(debug->debugMode)
395     {
396         LogDebug("Send RT signal to wrt-launcher(pid: "
397                 << wrtClient->m_sdkLauncherPid << ", status: " << success);
398         union sigval sv;
399         /* send real time signal with result to wrt-launcher */
400         if(success)
401         {
402             LogDebug("userData->portnum : " << debug->portnum);
403             sv.sival_int = debug->portnum;
404         }
405         else
406         {
407            sv.sival_int = -1;
408         }
409         sigqueue(wrtClient->m_sdkLauncherPid, SIGRTMIN, sv);
410     }
411
412     ApplicationDataSingleton::Instance().freeBundle();
413
414     LogDebug("Cleaning wrtClient launch resources...");
415     delete debug->pid;
416     delete debug;
417 }
418
419 void WrtClient::launchStep()
420 {
421     LogDebug("Launching widget ...");
422
423     m_widget =
424         WRT::CoreModuleSingleton::Instance().getRunnableWidgetObject(m_handle);
425     if (!m_widget) {
426         LogError("RunnableWidgetObject is NULL, stop launchStep");
427         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
428                     NextStepEvent());
429         return;
430     }
431
432     if (m_widgetState == WidgetState_Running) {
433         LogWarning("Widget already running, stop launchStep");
434         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
435                     NextStepEvent());
436         return;
437     }
438
439     if (m_widgetState == WidgetState_Authorizing) {
440         LogWarning("Widget already authorizing, stop launchStep");
441         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
442                     NextStepEvent());
443         return;
444     }
445
446     // Widget is not running, localized data can be updated
447     localizeWidgetModel();
448     LocalizationSetting::SetLanguageChangedCallback(
449             languageChangedCallback, this);
450
451     if (!checkWACTestCertififedWidget())
452     {
453         LogWarning("WAC Certificate failed, stop launchStep");
454         return;
455     }
456
457     m_widgetState = WidgetState_Authorizing;
458     if (!m_widget->CheckBeforeLaunch()) {
459         LogError("CheckBeforeLaunch failed, stop launchStep");
460         DPL::Event::ControllerEventHandler<NextStepEvent>::PostEvent(
461                     NextStepEvent());
462         return;
463     }
464     LogInfo("Widget launch accepted. Entering running state");
465     DPL::OptionalString startUrl = m_widget->GetModel()->RunningStartURL.Get();
466     m_widgetState = WidgetState_Running;
467     m_widget->PrepareView(DPL::ToUTF8String(*startUrl), NULL);
468
469     m_cbs.reset(new WRT::UserCallbacks);
470     m_cbs->loadFinish = loadFinishCallback;
471     m_cbs->resume = NULL;
472     m_cbs->suspend = NULL;
473     m_cbs->reset = NULL;
474
475     m_widget->SetUserCallbacks(m_cbs, this);
476     m_widget->Show();
477 }
478
479 void WrtClient::shutdownStep()
480 {
481     LogDebug("Closing Wrt connection ...");
482     if (m_initialized && m_widget) {
483         m_widgetState = WidgetState_Stopped;
484         m_widget->Hide();
485         m_widget.reset();
486         WRT::CoreModuleSingleton::Instance().Terminate();
487         m_initialized = false;
488     }
489     Quit();
490 }
491
492 int WrtClient::languageChangedCallback(void *data)
493 {
494     LogDebug("Language Changed");
495     WrtClient* wrtClient = static_cast<WrtClient*>(data);
496     WRT::WidgetModelPtr model = wrtClient->m_widget->GetModel();
497
498     LocalizationSetting::SetLocalization();
499
500     LanguageTagsList tags = LocalizationUtils::GetUserAgentLanguageTags();
501     if (model->LanguageTags.Get() != tags) {
502         // update localized data
503         wrtClient->localizeWidgetModel();
504
505         if (true == wrtClient->m_launched &&
506                 wrtClient->m_widgetState != WidgetState_Stopped) {
507             wrtClient->m_widget->Reset();
508         }
509     }
510     return 0;
511 }
512
513 int main(int argc,
514          char *argv[])
515 {
516     ADD_PROFILING_POINT("main-entered", "point");
517
518     // Output on stdout will be flushed after every newline character,
519     // even if it is redirected to a pipe. This is useful for running
520     // from a script and parsing output.
521     // (Standard behavior of stdlib is to use full buffering when
522     // redirected to a pipe, which means even after an end of line
523     // the output may not be flushed).
524     setlinebuf(stdout);
525
526     // set evas backend type
527     if (!getenv("ELM_ENGINE")) {
528         if (setenv("ELM_ENGINE", "gl", 1)) {
529                 LogDebug("Enable backend");
530         }
531     }
532
533     // Set log tagging
534     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT-CLIENT");
535
536     WrtClient app(argc, argv);
537     int ret = app.Exec();
538     LogDebug("App returned: " << ret);
539     ret = app.getReturnStatus();
540     LogDebug("WrtClient returned: " << ret);
541     return ret;
542 }