From 4aecb708fbac8999655041d200d8924e2f25bfbe Mon Sep 17 00:00:00 2001 From: "Piotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/Samsung Electronics" Date: Fri, 21 Feb 2020 14:39:13 +0100 Subject: [PATCH] Revert "[Application] Make launch() and launchAppControl() asynchronous" This reverts commit b6cff5d0cf62f059dc2cf5e64208d05794d31f5d. [Verification] TCT application - 100% TCT deprecated - 100% Change-Id: I1d1c42cfa5c5731ce329525b7007127b56de796b --- src/application/application_manager.cc | 401 +++++++++++++++------------------ src/application/application_manager.h | 3 +- 2 files changed, 182 insertions(+), 222 deletions(-) diff --git a/src/application/application_manager.cc b/src/application/application_manager.cc index a4b3057..74273f7 100644 --- a/src/application/application_manager.cc +++ b/src/application/application_manager.cc @@ -214,7 +214,7 @@ class TerminateHandler { return; \ } -void ApplicationManager::AsyncResponse(const PlatformResult& result, +void ApplicationManager::AsyncResponse(PlatformResult& result, std::shared_ptr* response) { ScopeLogger(); LogAndReportError(result, &(*response)->get()); @@ -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()) { - return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."); + int callback_id = -1; + const auto& callback = args.get(kCallbackId); + if (callback.is()) { + callback_id = static_cast(callback.get()); } - const picojson::object& app_control_obj = control.get(); - app_control_h tmp_app_control = nullptr; - auto result = ApplicationUtils::ApplicationControlToService(app_control_obj, &tmp_app_control); - std::unique_ptr::type, decltype(&app_control_destroy)> - app_control_ptr(tmp_app_control, &app_control_destroy); + std::shared_ptr response(new picojson::value(picojson::object())); + picojson::object& obj = response->get(); + obj.insert(std::make_pair(kCallbackId, picojson::value(static_cast(callback_id)))); - if (result.IsError()) { - LoggerE("Application control to service failed."); - return result; + const auto& app_id = args.get("id"); + if (!app_id.is()) { + PlatformResult ret = + LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."); + AsyncResponse(ret, &response); + return; } + const std::string& id = app_id.get(); - std::string app_id; - const auto& id = args.get("id"); - if (id.is()) { - app_id = id.get(); - } + auto launch = [id](const std::shared_ptr& 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()); + } else { + LoggerD("Launch request success"); + ReportSuccess(response->get()); + } + }; + + 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(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()) { + result = LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."); + AsyncResponse(result, &response); return; } + const picojson::object& app_control_obj = control.get(); - std::unique_ptr::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()) { - reply_callback_id = reply.get(); + std::string launch_mode_str; + const auto& launch_mode = control.get("launchMode"); + if (launch_mode.is()) { + launch_mode_str = launch_mode.get(); } - struct LaunchAppControlCallbackData { - ApplicationInstance* instance; - std::shared_ptr 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::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(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(); - 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())) { - 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(user_data); - - auto result = ApplicationUtils::TranslateAppControlError(launch_result); - - if (result.IsError()) { - LogAndReportError(result, &(callback_data->response->get())); - } else { - ReportSuccess(callback_data->response->get()); - } - - 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_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()) { - return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."); + std::string app_id; + const auto& id = args.get("id"); + if (id.is()) { + app_id = id.get(); } - const auto app_id_str = app_id.get(); - 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()) { + reply_callback = reply.get(); } - std::unique_ptr::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& 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(), + ("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()) { - callback_id = static_cast(callback.get()); - } + 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 response(new picojson::value(picojson::object())); - picojson::object& response_obj = response->get(); - response_obj.insert( - std::make_pair(kCallbackId, picojson::value(static_cast(callback_id)))); + picojson::value return_value = picojson::value(picojson::object()); + picojson::object& return_value_obj = return_value.get(); + ReplayCallbackData* reply_callback = static_cast(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())) { + return_value_obj.erase(data); + } + ReportSuccess(return_value_obj); + } else { + ReportError(return_value_obj); + } - std::unique_ptr::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 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(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())); - } else { - ReportSuccess(callback_data->response->get()); + // 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(), + ("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(), + ("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(), + ("app_control_send_launch_request returns APP_CONTROL_ERROR_APP_NOT_FOUND")); + return; + default: + LogAndReportError( + PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error."), + &response->get(), + ("app_control_send_launch_request returns: %d (%s)", ret, get_error_message(ret))); + return; + } + } + ReportSuccess(response->get()); }; - /* - * 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_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 diff --git a/src/application/application_manager.h b/src/application/application_manager.h index be0ebbf..c1fa8ad 100644 --- a/src/application/application_manager.h +++ b/src/application/application_manager.h @@ -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* response); + void AsyncResponse(common::PlatformResult& result, std::shared_ptr* response); void BroadcastEventHelper(const picojson::value& args, picojson::object& out, bool trusted); common::PlatformResult StartEventListener(const std::string& event_name, -- 2.7.4