Merge branch 'tizen_5.0' into tizen_5.5 16/225916/1 accepted/tizen/5.5/unified/20200225.140242 submit/tizen_5.5/20200225.093909
authorPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Tue, 25 Feb 2020 08:22:45 +0000 (09:22 +0100)
committerPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics <p.kosko@samsung.com>
Tue, 25 Feb 2020 09:12:04 +0000 (10:12 +0100)
Change-Id: I87da3bb68de8658d2330fe09dcd736acc5d809dd

1  2 
packaging/webapi-plugins.spec
src/application/application_manager.cc

@@@ -6,11 -6,9 +6,11 @@@
  %define crosswalk_extensions tizen-extensions-crosswalk
  
  %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions}
 +%define tizen_ut_build 0
 +
  
  Name:       webapi-plugins
- Version:    2.59
 -Version:    2.47
++Version:    2.60
  Release:    0
  License:    Apache-2.0 and BSD-3-Clause and MIT
  Group:      Development/Libraries
@@@ -443,220 -492,132 +443,219 @@@ void ApplicationManager::LaunchAppContr
      return;
    }
  
 -  std::string app_id;
 -  const auto& id = args.get("id");
 -  if (id.is<std::string>()) {
 -    app_id = id.get<std::string>();
 -  }
 +  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;
 +  std::string reply_callback_id;
    const auto& reply = args.get("replyCallback");
    if (reply.is<std::string>()) {
 -    reply_callback = reply.get<std::string>();
 +    reply_callback_id = reply.get<std::string>();
    }
  
 -  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");
 +  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};
 +
 +  if (!launch_app_user_data) {
 +    LoggerE("Memory allocation fail!");
 +    AsyncResponse(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error."), &response);
 +    return;
 +  }
  
 -    if (!app_id.empty()) {
 -      LoggerD("app_id: %s", app_id.c_str());
 +  app_control_reply_cb reply_callback = nullptr;
 +  if (!reply_callback_id.empty()) {
 +    launch_app_user_data->reply_callback_id = reply_callback_id;
  
 -      int ret = app_control_set_app_id(app_control_ptr.get(), app_id.c_str());
 +    reply_callback = [](app_control_h request, app_control_h reply, app_control_result_e result,
 +                        void* user_data) {
 +      ScopeLogger("reply_callback");
  
 -      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)));
 +      LaunchAppControlCallbackData* callback_data =
 +          static_cast<LaunchAppControlCallbackData*>(user_data);
 +      if (!callback_data) {
 +        LoggerD("reply_callback failed: user_data is nullptr");
          return;
        }
 -    }
  
 -    app_control_reply_cb callback = nullptr;
 -    struct ReplayCallbackData {
 -      ApplicationInstance* app_instance;
 -      std::string reply_callback;
 +      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 (!utils::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;
      };
 +  }
  
 -    ReplayCallbackData* user_data = nullptr;
 +  app_control_result_cb result_callback = [](app_control_h launch_request,
 +                                             app_control_error_e launch_result, void* user_data) {
 +    ScopeLogger("LaunchAppControl result_callback");
  
 -    if (!reply_callback.empty()) {
 -      user_data = new ReplayCallbackData();
 -      user_data->app_instance = &this->instance_;
 -      user_data->reply_callback = reply_callback;
 +    LaunchAppControlCallbackData* callback_data =
 +        static_cast<LaunchAppControlCallbackData*>(user_data);
  
 -      callback = [](app_control_h request, app_control_h reply, app_control_result_e result,
 -                    void* user_data) {
 -        LoggerD("send_launch_request callback");
 +    auto result = utils::TranslateAppControlError(launch_result);
  
 -        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);
 +    if (result.IsError()) {
 +      LogAndReportError(result, &(callback_data->response->get<picojson::object>()));
 +    } else {
 +      ReportSuccess(callback_data->response->get<picojson::object>());
 +    }
  
 -        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);
 -        }
 +    Instance::PostMessage(callback_data->instance, callback_data->response->serialize().c_str());
  
 -        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;
 -      };
 +    if (result.IsError() || (callback_data->reply_callback_id).empty()) {
 +      delete callback_data;
      }
 +  };
  
 -    const int retry_count = 3;
 +  /*
 +   * 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 = utils::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");
 +  }
 +}
  
 -    int retry = 0;
 -    int ret = 0;
 +namespace {
  
 -    while (retry < retry_count) {
 -      LoggerD("Calling launch request. Attempt number: %d", retry);
 +PlatformResult TranslateLaunchError(app_control_error_e return_code) {
 +  ScopeLogger();
  
 -      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;
 -      }
 +  auto result = utils::TranslateAppControlError(return_code);
 +  if (ErrorCode::SECURITY_ERR == result.error_code()) {
 +    result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
 +  }
  
 -      // delay 300ms for each retry
 -      struct timespec sleep_time = {0, 300L * 1000L * 1000L};
 -      nanosleep(&sleep_time, nullptr);
 -      ++retry;
 -    }
 +  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.");
 +  }
 +  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::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
 +      app_control_ptr(tmp_app_control, &app_control_destroy);
 +
 +  if (!app_id_str.empty()) {
 +    LoggerD("app_id: %s", app_id_str.c_str());
 +
 +    int ret = app_control_set_app_id(app_control_ptr.get(), app_id_str.c_str());
  
      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;
 -      }
 +      LoggerE("Failed to set app id: %d (%s)", ret, get_error_message(ret));
 +      return PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
      }
 -    ReportSuccess(response->get<picojson::object>());
 +  }
 +
 +  *app_control = app_control_ptr.release();
 +
 +  return PlatformResult(ErrorCode::NO_ERROR);
 +}
 +
 +}  // namespace
 +void ApplicationManager::Launch(const picojson::value& args) {
 +  ScopeLogger();
 +
 +  int callback_id = -1;
 +  const auto& callback = args.get(kCallbackId);
 +  if (callback.is<double>()) {
 +    callback_id = static_cast<int>(callback.get<double>());
 +  }
 +
 +  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))));
 +
 +  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;
 +  }
 +
 +  std::unique_ptr<std::remove_pointer<app_control_h>::type, decltype(&app_control_destroy)>
 +      app_control_ptr(app_control, &app_control_destroy);
 +
 +  struct LaunchCallbackData {
 +    ApplicationInstance* instance;
 +    std::shared_ptr<picojson::value> response;
 +  }* launch_user_data = new (std::nothrow) LaunchCallbackData{&this->instance_, response};
 +
 +  app_control_result_cb result_callback = [](app_control_h launch_request,
 +                                             app_control_error_e launch_result, void* user_data) {
 +    ScopeLogger("Launch result_callback");
 +
 +    LaunchCallbackData* callback_data = static_cast<LaunchCallbackData*>(user_data);
 +
 +    auto result = TranslateLaunchError(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());
 +
 +    delete callback_data;
    };
  
 -  launch(response);
 -  Instance::PostMessage(&this->instance_, response->serialize().c_str());
 +  /*
 +   * 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_resume_request(
-           app_control_ptr.get(), result_callback, launch_user_data)));
++  auto launch_result = TranslateLaunchError(static_cast<app_control_error_e>(
++      app_control_send_resume_request(app_control_ptr.get(), result_callback, launch_user_data)));
 +
 +  if (launch_result.IsError()) {
 +    delete launch_user_data;
 +    AsyncResponse(launch_result, &response);
 +  } else {
 +    LoggerD("App launched");
 +  }
  }
  
  // internal impl of app_control_foreach_app_matched() for handling APP_CONTROL_ERROR_APP_NOT_FOUND