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>());
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();
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