Revert "[Application] Make launch() and launchAppControl() asynchronous" 40/225740/3
authorPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Fri, 21 Feb 2020 13:39:13 +0000 (14:39 +0100)
committerPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Mon, 24 Feb 2020 10:44:04 +0000 (11:44 +0100)
This reverts commit b6cff5d0cf62f059dc2cf5e64208d05794d31f5d.

[Verification]
TCT application - 100%
TCT deprecated - 100%

Change-Id: I1d1c42cfa5c5731ce329525b7007127b56de796b

src/application/application_manager.cc
src/application/application_manager.h

index a4b3057..74273f7 100644 (file)
@@ -214,7 +214,7 @@ class TerminateHandler {
     return;                                                        \
   }
 
-void ApplicationManager::AsyncResponse(const PlatformResult& result,
+void ApplicationManager::AsyncResponse(PlatformResult& result,
                                        std::shared_ptr<picojson::value>* response) {
   ScopeLogger();
   LogAndReportError(result, &(*response)->get<picojson::object>());
@@ -376,51 +376,81 @@ void ApplicationManager::Kill(const picojson::value& args) {
   kill();
 }
 
-namespace {
-
-PlatformResult PrepareAppControlForLaunchAppControl(const picojson::value& args,
-                                                    app_control_h* app_control) {
+void ApplicationManager::Launch(const picojson::value& args) {
   ScopeLogger();
 
-  const auto& control = args.get("appControl");
-  if (!control.is<picojson::object>()) {
-    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+  int callback_id = -1;
+  const auto& callback = args.get(kCallbackId);
+  if (callback.is<double>()) {
+    callback_id = static_cast<int>(callback.get<double>());
   }
-  const picojson::object& app_control_obj = control.get<picojson::object>();
 
-  app_control_h tmp_app_control = nullptr;
-  auto result = ApplicationUtils::ApplicationControlToService(app_control_obj, &tmp_app_control);
-  std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
-      app_control_ptr(tmp_app_control, &app_control_destroy);
+  std::shared_ptr<picojson::value> response(new picojson::value(picojson::object()));
+  picojson::object& obj = response->get<picojson::object>();
+  obj.insert(std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
 
-  if (result.IsError()) {
-    LoggerE("Application control to service failed.");
-    return result;
+  const auto& app_id = args.get("id");
+  if (!app_id.is<std::string>()) {
+    PlatformResult ret =
+        LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+    AsyncResponse(ret, &response);
+    return;
   }
+  const std::string& id = app_id.get<std::string>();
 
-  std::string app_id;
-  const auto& id = args.get("id");
-  if (id.is<std::string>()) {
-    app_id = id.get<std::string>();
-  }
+  auto launch = [id](const std::shared_ptr<picojson::value>& response) -> void {
+    ScopeLogger("launch");
+    PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
+    const char* app_id = id.c_str();
+    const int retry_count = 3;
 
-  if (!app_id.empty()) {
-    LoggerD("app_id: %s", app_id.c_str());
+    int retry = 0;
+    int ret = 0;
 
-    int ret = app_control_set_app_id(app_control_ptr.get(), app_id.c_str());
+    while (retry < retry_count) {
+      ret = aul_open_app(app_id);
 
-    if (APP_CONTROL_ERROR_NONE != ret) {
-      LoggerE("Failed to set app id: %d (%s)", ret, get_error_message(ret));
-      return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+      if (ret >= 0) {
+        break;
+      }
+
+      // delay 300ms for each retry
+      struct timespec sleep_time = {0, 300L * 1000L * 1000L};
+      nanosleep(&sleep_time, nullptr);
+      ++retry;
+
+      LoggerD("Retry launch request: %d", retry);
     }
-  }
 
-  *app_control = app_control_ptr.release();
+    if (ret < 0) {
+      result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error has occurred.");
+
+      LoggerD("Aul open return: %d (%s)", ret, get_error_message(ret));
+      switch (ret) {
+        case AUL_R_EINVAL:
+        case AUL_R_ERROR:
+        case AUL_R_ENOAPP:
+          result =
+              LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Launchpad returns not found error.",
+                                 ("aul_open_app returns Not Found error"));
+          break;
 
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
+        case AUL_R_ECOMM:
+          result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Internal IPC error has occurred.",
+                                      ("aul_open_app returns internal IPC error"));
+          break;
+      }
 
-}  // namespace
+      LogAndReportError(result, &response->get<picojson::object>());
+    } else {
+      LoggerD("Launch request success");
+      ReportSuccess(response->get<picojson::object>());
+    }
+  };
+
+  launch(response);
+  Instance::PostMessage(&this->instance_, response->serialize().c_str());
+}
 
 void ApplicationManager::LaunchAppControl(const picojson::value& args) {
   ScopeLogger();
@@ -436,227 +466,158 @@ void ApplicationManager::LaunchAppControl(const picojson::value& args) {
   response_obj.insert(
       std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
 
-  app_control_h app_control = nullptr;
-  auto prepare_app_control_result = PrepareAppControlForLaunchAppControl(args, &app_control);
-  if (prepare_app_control_result.IsError()) {
-    AsyncResponse(LogAndCreateResult(prepare_app_control_result), &response);
+  PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
+  const auto& control = args.get("appControl");
+  if (!control.is<picojson::object>()) {
+    result = LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+    AsyncResponse(result, &response);
     return;
   }
+  const picojson::object& app_control_obj = control.get<picojson::object>();
 
-  std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
-      app_control_ptr(app_control, &app_control_destroy);
-
-  std::string reply_callback_id;
-  const auto& reply = args.get("replyCallback");
-  if (reply.is<std::string>()) {
-    reply_callback_id = reply.get<std::string>();
+  std::string launch_mode_str;
+  const auto& launch_mode = control.get("launchMode");
+  if (launch_mode.is<std::string>()) {
+    launch_mode_str = launch_mode.get<std::string>();
   }
 
-  struct LaunchAppControlCallbackData {
-    ApplicationInstance* instance;
-    std::shared_ptr<picojson::value> response;
-    std::string reply_callback_id;
-  }* launch_app_user_data = new (std::nothrow)
-      LaunchAppControlCallbackData{&this->instance_, response, reply_callback_id};
+  app_control_h app_control = nullptr;
+  result = ApplicationUtils::ApplicationControlToService(app_control_obj, &app_control);
+  std::shared_ptr<std::remove_pointer<app_control_h>::type> app_control_ptr(
+      app_control, &app_control_destroy);  // automatically release the memory
 
-  if (!launch_app_user_data) {
-    LoggerE("Memory allocation fail!");
-    AsyncResponse(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error."), &response);
+  if (result.IsError()) {
+    LoggerE("Application control to service failed.");
+    AsyncResponse(result, &response);
     return;
   }
 
-  app_control_reply_cb reply_callback = nullptr;
-  if (!reply_callback_id.empty()) {
-    launch_app_user_data->reply_callback_id = reply_callback_id;
-
-    reply_callback = [](app_control_h request, app_control_h reply, app_control_result_e result,
-                        void* user_data) {
-      ScopeLogger("reply_callback");
-
-      LaunchAppControlCallbackData* callback_data =
-          static_cast<LaunchAppControlCallbackData*>(user_data);
-      if (!callback_data) {
-        LoggerD("reply_callback failed: user_data is nullptr");
-        return;
-      }
-
-      picojson::value return_value = picojson::value(picojson::object());
-      picojson::object& return_value_obj = return_value.get<picojson::object>();
-      return_value_obj.insert(
-          std::make_pair(kListenerId, picojson::value(callback_data->reply_callback_id)));
-
-      if (APP_CONTROL_RESULT_SUCCEEDED == result) {
-        LoggerD("App started");
-        return_value_obj.insert(std::make_pair("data", picojson::value(picojson::array())));
-        if (!ApplicationUtils::ServiceToApplicationControlDataArray(
-                reply, &return_value_obj.find("data")->second.get<picojson::array>())) {
-          return_value_obj.erase("data");
-        }
-        ReportSuccess(return_value_obj);
-      } else {
-        ReportError(return_value_obj);
-      }
-
-      Instance::PostMessage(callback_data->instance, return_value.serialize().c_str());
-      delete callback_data;
-    };
-  }
-
-  app_control_result_cb result_callback = [](app_control_h launch_request,
-                                             app_control_error_e launch_result, void* user_data) {
-    ScopeLogger("LaunchAppControl result_callback");
-
-    LaunchAppControlCallbackData* callback_data =
-        static_cast<LaunchAppControlCallbackData*>(user_data);
-
-    auto result = ApplicationUtils::TranslateAppControlError(launch_result);
-
-    if (result.IsError()) {
-      LogAndReportError(result, &(callback_data->response->get<picojson::object>()));
-    } else {
-      ReportSuccess(callback_data->response->get<picojson::object>());
-    }
-
-    Instance::PostMessage(callback_data->instance, callback_data->response->serialize().c_str());
-
-    if (result.IsError() || (callback_data->reply_callback_id).empty()) {
-      delete callback_data;
-    }
-  };
-
-  /*
-   * TODO: Observe how often app_control_send_launch_request_async tries to launch the application.
-   * Previous implementation, using synchronous app_control_send_launch_request,
-   * tries to launch the application 3 times, before reporting an error.
-   * New implementation, using app_control_send_launch_request_async makes only one attempt.
-   * If problems, such as failed application start occur, multiple attempts may solve the problem.
-   */
-  auto launch_result = ApplicationUtils::TranslateAppControlError(
-      static_cast<app_control_error_e>(app_control_send_launch_request_async(
-          app_control_ptr.get(), result_callback, reply_callback, launch_app_user_data)));
-
-  if (launch_result.IsError()) {
-    delete launch_app_user_data;
-    AsyncResponse(launch_result, &response);
-  } else {
-    LoggerD("App launched");
-  }
-}
-
-namespace {
-
-PlatformResult TranslateLaunchError(app_control_error_e return_code) {
-  ScopeLogger();
-
-  auto result = ApplicationUtils::TranslateAppControlError(return_code);
-  if (ErrorCode::SECURITY_ERR == result.error_code()) {
-    result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
-  }
-
-  return result;
-}
-
-PlatformResult PrepareAppControlForLaunch(const picojson::value& args, app_control_h* app_control) {
-  ScopeLogger();
-
-  const auto& app_id = args.get("id");
-  if (!app_id.is<std::string>()) {
-    return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+  std::string app_id;
+  const auto& id = args.get("id");
+  if (id.is<std::string>()) {
+    app_id = id.get<std::string>();
   }
-  const auto app_id_str = app_id.get<std::string>();
 
-  app_control_h tmp_app_control = nullptr;
-  int result = app_control_create(&tmp_app_control);
-  if (APP_CONTROL_ERROR_NONE != result) {
-    LoggerD("app_control_create() failed: %d (%s)", result, get_error_message(result));
-    return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.");
+  std::string reply_callback;
+  const auto& reply = args.get("replyCallback");
+  if (reply.is<std::string>()) {
+    reply_callback = reply.get<std::string>();
   }
 
-  std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
-      app_control_ptr(tmp_app_control, &app_control_destroy);
+  auto launch = [this, app_control_ptr, app_id, launch_mode_str,
+                 reply_callback](const std::shared_ptr<picojson::value>& response) -> void {
+    ScopeLogger("Entered into asynchronous function, launch");
 
-  if (!app_id_str.empty()) {
-    LoggerD("app_id: %s", app_id_str.c_str());
+    if (!app_id.empty()) {
+      LoggerD("app_id: %s", app_id.c_str());
 
-    int ret = app_control_set_app_id(app_control_ptr.get(), app_id_str.c_str());
+      int ret = app_control_set_app_id(app_control_ptr.get(), app_id.c_str());
 
-    if (APP_CONTROL_ERROR_NONE != ret) {
-      LoggerE("Failed to set app id: %d (%s)", ret, get_error_message(ret));
-      return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
+      if (APP_CONTROL_ERROR_NONE != ret) {
+        LogAndReportError(
+            PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
+            &response->get<picojson::object>(),
+            ("Failed to set app id: %d (%s)", ret, get_error_message(ret)));
+        return;
+      }
     }
-  }
 
-  *app_control = app_control_ptr.release();
+    app_control_reply_cb callback = nullptr;
+    struct ReplayCallbackData {
+      ApplicationInstance* app_instance;
+      std::string reply_callback;
+    };
 
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
+    ReplayCallbackData* user_data = nullptr;
 
-}  // namespace
-void ApplicationManager::Launch(const picojson::value& args) {
-  ScopeLogger();
+    if (!reply_callback.empty()) {
+      user_data = new ReplayCallbackData();
+      user_data->app_instance = &this->instance_;
+      user_data->reply_callback = reply_callback;
 
-  int callback_id = -1;
-  const auto& callback = args.get(kCallbackId);
-  if (callback.is<double>()) {
-    callback_id = static_cast<int>(callback.get<double>());
-  }
+      callback = [](app_control_h request, app_control_h reply, app_control_result_e result,
+                    void* user_data) {
+        LoggerD("send_launch_request callback");
 
-  std::shared_ptr<picojson::value> response(new picojson::value(picojson::object()));
-  picojson::object& response_obj = response->get<picojson::object>();
-  response_obj.insert(
-      std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
+        picojson::value return_value = picojson::value(picojson::object());
+        picojson::object& return_value_obj = return_value.get<picojson::object>();
+        ReplayCallbackData* reply_callback = static_cast<ReplayCallbackData*>(user_data);
 
-  app_control_h app_control = nullptr;
-  auto prepare_app_control_result = PrepareAppControlForLaunch(args, &app_control);
-  if (prepare_app_control_result.IsError()) {
-    AsyncResponse(LogAndCreateResult(prepare_app_control_result), &response);
-    return;
-  }
+        if (APP_CONTROL_RESULT_SUCCEEDED == result) {
+          const std::string data = "data";
+          return_value_obj.insert(std::make_pair(data, picojson::value(picojson::array())));
+          if (!ApplicationUtils::ServiceToApplicationControlDataArray(
+                  reply, &return_value_obj.find(data)->second.get<picojson::array>())) {
+            return_value_obj.erase(data);
+          }
+          ReportSuccess(return_value_obj);
+        } else {
+          ReportError(return_value_obj);
+        }
 
-  std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
-      app_control_ptr(app_control, &app_control_destroy);
+        return_value_obj.insert(
+            std::make_pair("listenerId", picojson::value(reply_callback->reply_callback)));
+        Instance::PostMessage(reply_callback->app_instance, return_value.serialize().c_str());
+        delete reply_callback;
+      };
+    }
 
-  struct LaunchCallbackData {
-    ApplicationInstance* instance;
-    std::shared_ptr<picojson::value> response;
-  }* launch_user_data = new (std::nothrow) LaunchCallbackData{&this->instance_, response};
+    const int retry_count = 3;
 
-  app_control_result_cb result_callback = [](app_control_h launch_request,
-                                             app_control_error_e launch_result, void* user_data) {
-    ScopeLogger("Launch result_callback");
+    int retry = 0;
+    int ret = 0;
 
-    LaunchCallbackData* callback_data = static_cast<LaunchCallbackData*>(user_data);
+    while (retry < retry_count) {
+      LoggerD("Calling launch request. Attempt number: %d", retry);
 
-    auto result = TranslateLaunchError(launch_result);
+      ret = app_control_send_launch_request(app_control_ptr.get(), callback, user_data);
+      LoggerD("App control launch request returned: %d, %s", ret, get_error_message(ret));
+      if (APP_CONTROL_ERROR_NONE == ret) {
+        break;
+      }
 
-    if (result.IsError()) {
-      LogAndReportError(result, &(callback_data->response->get<picojson::object>()));
-    } else {
-      ReportSuccess(callback_data->response->get<picojson::object>());
+      // delay 300ms for each retry
+      struct timespec sleep_time = {0, 300L * 1000L * 1000L};
+      nanosleep(&sleep_time, nullptr);
+      ++retry;
     }
 
-    Instance::PostMessage(callback_data->instance, callback_data->response->serialize().c_str());
-
-    delete callback_data;
+    if (APP_CONTROL_ERROR_NONE != ret) {
+      delete user_data;
+
+      switch (ret) {
+        case APP_CONTROL_ERROR_INVALID_PARAMETER:
+          LogAndReportError(
+              PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter returned."),
+              &response->get<picojson::object>(),
+              ("app_control_send_launch_request returns APP_CONTROL_ERROR_INVALID_PARAMETER"));
+          return;
+        case APP_CONTROL_ERROR_OUT_OF_MEMORY:
+          LogAndReportError(
+              PlatformResult(ErrorCode::UNKNOWN_ERR, "Out of memory."),
+              &response->get<picojson::object>(),
+              ("app_control_send_launch_request returns APP_CONTROL_ERROR_OUT_OF_MEMORY"));
+          return;
+        case APP_CONTROL_ERROR_LAUNCH_REJECTED:
+        case APP_CONTROL_ERROR_APP_NOT_FOUND:
+          LogAndReportError(
+              PlatformResult(ErrorCode::NOT_FOUND_ERR, "No matched application found."),
+              &response->get<picojson::object>(),
+              ("app_control_send_launch_request returns APP_CONTROL_ERROR_APP_NOT_FOUND"));
+          return;
+        default:
+          LogAndReportError(
+              PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error."),
+              &response->get<picojson::object>(),
+              ("app_control_send_launch_request returns: %d (%s)", ret, get_error_message(ret)));
+          return;
+      }
+    }
+    ReportSuccess(response->get<picojson::object>());
   };
 
-  /*
-   * TODO: Observe how often app_control_send_launch_request_async tries to launch the application.
-   * Previous implementation, using synchronous app_control_send_launch_request,
-   * tries to launch the application 3 times, before reporting an error.
-   * New implementation, using app_control_send_launch_request_async makes only one attempt.
-   * If problems, such as failed application start occur, multiple attempts may solve the problem.
-   */
-  auto launch_result =
-      TranslateLaunchError(static_cast<app_control_error_e>(app_control_send_launch_request_async(
-          app_control_ptr.get(), result_callback, nullptr, launch_user_data)));
-
-  if (launch_result.IsError()) {
-    delete launch_user_data;
-    AsyncResponse(launch_result, &response);
-  } else {
-    LoggerD("App launched");
-  }
+  launch(response);
+  Instance::PostMessage(&this->instance_, response->serialize().c_str());
 }
 
 // internal impl of app_control_foreach_app_matched() for handling APP_CONTROL_ERROR_APP_NOT_FOUND
index be0ebbf..c1fa8ad 100644 (file)
@@ -64,8 +64,7 @@ class ApplicationManager {
   void StartAppInfoEventListener(picojson::object* out);
   void StopAppInfoEventListener();
   void GetApplicationInformationSize(const picojson::value& args, picojson::object* out);
-  void AsyncResponse(const common::PlatformResult& result,
-                     std::shared_ptr<picojson::value>* response);
+  void AsyncResponse(common::PlatformResult& result, std::shared_ptr<picojson::value>* response);
 
   void BroadcastEventHelper(const picojson::value& args, picojson::object& out, bool trusted);
   common::PlatformResult StartEventListener(const std::string& event_name,