Assure proper termination using context session 66/108966/5 accepted/tizen_3.0.m2_common accepted/tizen_3.0.m2_mobile accepted/tizen_3.0.m2_tv accepted/tizen_3.0.m2_wearable tizen_3.0.m2 accepted/tizen/3.0.m2/common/20170111.094130 accepted/tizen/3.0.m2/mobile/20170111.043120 accepted/tizen/3.0.m2/tv/20170111.043138 accepted/tizen/3.0.m2/wearable/20170111.043201 accepted/tizen/3.0/common/20170110.125811 accepted/tizen/3.0/ivi/20170110.044431 accepted/tizen/3.0/mobile/20170110.044338 accepted/tizen/3.0/tv/20170110.044355 accepted/tizen/3.0/wearable/20170110.044412 submit/tizen_3.0.m2/20170109.152207 submit/tizen_3.0.m2/20170111.004805 submit/tizen_3.0/20170109.151907
authorYoungsoo Choi <kenshin.choi@samsung.com>
Wed, 4 Jan 2017 09:01:10 +0000 (18:01 +0900)
committerYoungsoo Choi <kenshin.choi@samsung.com>
Mon, 9 Jan 2017 15:11:11 +0000 (00:11 +0900)
Current main loop quits when closing window callback is called.
Btw, it does not assure proper termination of changing watch face
because context session stops too early and callback can not be called
and then dead lock happens.

So, this CL extends the main loop until all the context sessions are finished
and covers following termination scenarios.

* h/w back key
* exit pop up menu
* exit command |pkgcmd -k|
* uninstall command |pkgcmd -u| while webapp runs
* changing watch face

Bug: http://suprem.sec.samsung.net/jira/browse/TWF-2765

Change-Id: I1767ef5f14e393ffc59668b0b9925d781abfd2f5
Signed-off-by: Youngsoo Choi <kenshin.choi@samsung.com>
extensions/renderer/xwalk_extension_renderer_controller.cc
extensions/renderer/xwalk_extension_renderer_controller.h
runtime/browser/runtime_process.cc
runtime/browser/web_application.cc
runtime/browser/web_application.h

index 59e45b70ba654c6cb840745d2336242e238a99e3..01c1ecedc6b32b95aba46da73e91609ff436588e 100755 (executable)
@@ -22,6 +22,9 @@
 
 namespace extensions {
 
+// static
+int XWalkExtensionRendererController::plugin_session_count = 0;
+
 namespace {
 
 void CreateExtensionModules(XWalkExtensionClient* client,
@@ -81,12 +84,16 @@ void XWalkExtensionRendererController::DidCreateScriptContext(
   CreateExtensionModules(extensions_client_.get(), module_system);
 
   module_system->Initialize();
+  plugin_session_count++;
+  LOGGER(DEBUG) << "plugin_session_count : " << plugin_session_count;
 }
 
 void XWalkExtensionRendererController::WillReleaseScriptContext(
     v8::Handle<v8::Context> context) {
   v8::Context::Scope contextScope(context);
   XWalkModuleSystem::ResetModuleSystemFromContext(context);
+  plugin_session_count--;
+  LOGGER(DEBUG) << "plugin_session_count : " << plugin_session_count;
 }
 
 void XWalkExtensionRendererController::OnReceivedIPCMessage(
index 4927d210c492f875b7676ba514d0ecd981659e01..95e3145421831bcf59c8ca686b200a979a0447ce 100755 (executable)
@@ -20,6 +20,7 @@ class XWalkExtensionClient;
 class XWalkExtensionRendererController {
  public:
   static XWalkExtensionRendererController& GetInstance();
+  static int plugin_session_count;
 
   void DidCreateScriptContext(v8::Handle<v8::Context> context);
   void WillReleaseScriptContext(v8::Handle<v8::Context> context);
index 859aa3a6b0ce662ab064ac562c414bc7c0e5d670..83d7645f924866cf7b08819f8f8aa1d504971895 100755 (executable)
@@ -28,6 +28,7 @@
 #include "common/command_line.h"
 #include "common/logger.h"
 #include "common/profiler.h"
+#include "extensions/renderer/xwalk_extension_renderer_controller.h"
 #include "runtime/browser/runtime.h"
 #include "runtime/common/constants.h"
 #include "runtime/browser/prelauncher.h"
@@ -35,6 +36,7 @@
 
 #include "runtime/browser/ui_runtime.h"
 
+using namespace extensions;
 bool g_prelaunch = false;
 
 #ifdef WATCH_FACE_FEATURE_SUPPORT
@@ -132,16 +134,22 @@ int real_main(int argc, char* argv[]) {
     std::unique_ptr<runtime::Runtime> runtime =
         runtime::Runtime::MakeRuntime(appdata);
     ret = runtime->Exec(argc, argv);
-    if (runtime->is_on_terminate_called) {
-      LOGGER(INFO) << "Defer termination of main loop";
+    if (ret)
+      LOGGER(ERROR) << "Exec returns non zero.";
+    LOGGER(DEBUG) << "plugin_session_count : " <<
+        XWalkExtensionRendererController::plugin_session_count;
+    if (XWalkExtensionRendererController::plugin_session_count > 0) {
+      LOGGER(DEBUG) << "Defer termination of main loop";
       ecore_main_loop_begin();
     }
     runtime.reset();
   }
+  LOGGER(DEBUG) << "ewk_shutdown";
   ewk_shutdown();
   elm_shutdown();
   elm_exit();
 
+  LOGGER(DEBUG) << "EXIT_SUCCESS";
   return EXIT_SUCCESS;
 }
 
index 9a5d50b3987ddd5102c27956dd3b4355ef0ad865..68143a8253b4b69fe6169cd77cf4fd8a7217ce1d 100755 (executable)
@@ -37,6 +37,7 @@
 #include "common/profiler.h"
 #include "common/resource_manager.h"
 #include "common/string_utils.h"
+#include "extensions/renderer/xwalk_extension_renderer_controller.h"
 #include "runtime/browser/native_window.h"
 #include "runtime/browser/notification_manager.h"
 #include "runtime/browser/popup.h"
 #error INJECTED_BUNDLE_PATH is not set.
 #endif
 
+#define TIMER_INTERVAL 0.1
+
+using namespace extensions;
+
 namespace runtime {
 
 namespace {
@@ -222,8 +227,10 @@ static void InitializeNotificationCallback(Ewk_Context* ewk_context,
 static Eina_Bool ExitAppIdlerCallback(void* data) {
   WebApplication* app = static_cast<WebApplication*>(data);
 
-  if (app)
+  if (app) {
+    LOGGER(DEBUG) << "Terminate";
     app->Terminate();
+  }
 
   return ECORE_CALLBACK_CANCEL;
 }
@@ -285,6 +292,7 @@ WebApplication::WebApplication(
       debug_mode_(false),
       verbose_mode_(false),
       lang_changed_mode_(false),
+      is_terminate_called_(false),
       ewk_context_(
           ewk_context_new_with_injected_bundle_path(INJECTED_BUNDLE_PATH)),
       has_ownership_of_ewk_context_(true),
@@ -303,6 +311,7 @@ WebApplication::WebApplication(
     : launched_(false),
       debug_mode_(false),
       verbose_mode_(false),
+      is_terminate_called_(false),
       ewk_context_(context),
       has_ownership_of_ewk_context_(false),
       window_(window),
@@ -637,23 +646,28 @@ void WebApplication::Suspend() {
 }
 
 void WebApplication::Terminate() {
+  is_terminate_called_ = true;
   if (terminator_) {
+    LOGGER(DEBUG) << "terminator_";
     terminator_();
   } else {
+    LOGGER(ERROR) << "There's no registered terminator.";
     elm_exit();
   }
   auto extension_server = extensions::XWalkExtensionServer::GetInstance();
-  LOGGER(INFO) << "Shutdown extension server";
+  LOGGER(DEBUG) << "Shutdown extension server";
   extension_server->Shutdown();
 }
 
 void WebApplication::ClosePageFromOnTerminate() {
+  LOGGER(DEBUG);
   auto it = view_stack_.begin();
   if (it != view_stack_.end()) {
     runtime::Runtime::is_on_terminate_called = true;
     for (; it != view_stack_.end(); ++it) {
       (*it)->ReplyToJavascriptDialog();
       view_stack_.front()->SetVisibility(false);
+      LOGGER(DEBUG) << "ewk_view_page_close";
       ewk_view_page_close((*it)->evas_object());
     }
   }
@@ -692,7 +706,13 @@ void WebApplication::RemoveWebViewFromStack(WebView* view) {
   }
 
   if (view_stack_.size() == 0) {
-    Terminate();
+    // If |Terminate()| hasn't been called,
+    // main loop shouldn't be terminated here.
+    if (!is_terminate_called_) {
+      auto extension_server = XWalkExtensionServer::GetInstance();
+      LOGGER(DEBUG) << "Shutdown extension server";
+      extension_server->Shutdown();
+    }
   } else if (current != view_stack_.front()) {
     view_stack_.front()->SetVisibility(true);
     window_->SetContent(view_stack_.front()->evas_object());
@@ -707,14 +727,43 @@ void WebApplication::RemoveWebViewFromStack(WebView* view) {
                   view);
 }
 
+Eina_Bool WebApplication::CheckPluginSession(void* user_data)
+{
+  WebApplication* that = static_cast<WebApplication*>(user_data);
+  if(XWalkExtensionRendererController::plugin_session_count > 0) {
+    LOGGER(ERROR) << "plugin_session_count : " <<
+        XWalkExtensionRendererController::plugin_session_count;
+    return ECORE_CALLBACK_RENEW;
+  }
+  LOGGER(DEBUG) << "plugin_session_count : " <<
+      XWalkExtensionRendererController::plugin_session_count;
+  LOGGER(DEBUG) << "Execute deferred termination of main loop";
+  if (that->is_terminate_called_) {
+    ecore_main_loop_quit();
+  } else {
+    if (that->terminator_) {
+      LOGGER(DEBUG) << "terminator_";
+      that->terminator_();
+    } else {
+      LOGGER(ERROR) << "There's no registered terminator.";
+      elm_exit();
+    }
+  }
+  return ECORE_CALLBACK_CANCEL;
+}
+
 void WebApplication::OnClosedWebView(WebView* view) {
+  Ecore_Timer* timeout_id = NULL;
   // Reply to javascript dialog for preventing freeze issue.
   view->ReplyToJavascriptDialog();
   RemoveWebViewFromStack(view);
 
-  if (runtime::Runtime::is_on_terminate_called) {
-    LOGGER(INFO) << "Execute deferred termination of main loop";
-    ecore_main_loop_quit();
+  LOGGER(DEBUG) << "plugin_session_count : " <<
+      XWalkExtensionRendererController::plugin_session_count;
+  if (XWalkExtensionRendererController::plugin_session_count > 0) {
+    timeout_id = ecore_timer_add(TIMER_INTERVAL, CheckPluginSession, this);
+    if (!timeout_id)
+      LOGGER(ERROR) << "It's failed to create timer";
   }
 }
 
@@ -831,6 +880,7 @@ void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
       if(enabled)
         view->EvalJavascript(kBackKeyEventScript);
       if (!view->Backward()) {
+        LOGGER(DEBUG) << "Terminate";
         Terminate();
       }
     }
@@ -846,6 +896,7 @@ void WebApplication::OnHardwareKey(WebView* view, const std::string& keyname) {
         (app_data_->widget_info() != NULL &&
          app_data_->widget_info()->view_modes() == "windowed")) {
       if (!view->Backward()) {
+        LOGGER(DEBUG) << "Terminate";
         Terminate();
       }
     }
index 751e809b9fb7015b44aea12513cc4bd75083f299..48665e8dea860aef1cfc949a64c8cb78a39024e8 100755 (executable)
@@ -106,6 +106,7 @@ class WebApplication : public WebView::EventListener {
 #ifdef MANUAL_ROTATE_FEATURE_SUPPORT
   virtual void OnRotatePrepared(WebView* view);
 #endif // MANUAL_ROTATE_FEATURE_SUPPORT
+  static Eina_Bool CheckPluginSession(void* user_data);
 
  private:
   bool Initialize();
@@ -130,6 +131,7 @@ class WebApplication : public WebView::EventListener {
   bool debug_mode_;
   bool verbose_mode_;
   bool lang_changed_mode_;
+  bool is_terminate_called_;
   Ewk_Context* ewk_context_;
   bool has_ownership_of_ewk_context_;
   NativeWindow* window_;