return; \
}
-void ApplicationManager::AsyncResponse(PlatformResult& result,
+void ApplicationManager::AsyncResponse(const PlatformResult& result,
std::shared_ptr<picojson::value>* response) {
ScopeLogger();
LogAndReportError(result, &(*response)->get<picojson::object>());
kill();
}
-void ApplicationManager::Launch(const picojson::value& args) {
+namespace {
+
+PlatformResult PrepareAppControlForLaunchAppControl(const picojson::value& args,
+ app_control_h* app_control) {
ScopeLogger();
- int callback_id = -1;
- const auto& callback = args.get(kCallbackId);
- if (callback.is<double>()) {
- callback_id = static_cast<int>(callback.get<double>());
+ const auto& control = args.get("appControl");
+ if (!control.is<picojson::object>()) {
+ return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed.");
}
+ const picojson::object& app_control_obj = control.get<picojson::object>();
- 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))));
+ 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);
- 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;
+ if (result.IsError()) {
+ LoggerE("Application control to service failed.");
+ return result;
}
- const std::string& id = app_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;
-
- int retry = 0;
- int ret = 0;
- while (retry < retry_count) {
- ret = aul_open_app(app_id);
+ std::string app_id;
+ const auto& id = args.get("id");
+ if (id.is<std::string>()) {
+ app_id = id.get<std::string>();
+ }
- if (ret >= 0) {
- break;
- }
+ if (!app_id.empty()) {
+ LoggerD("app_id: %s", app_id.c_str());
- // delay 300ms for each retry
- struct timespec sleep_time = {0, 300L * 1000L * 1000L};
- nanosleep(&sleep_time, nullptr);
- ++retry;
+ int ret = app_control_set_app_id(app_control_ptr.get(), app_id.c_str());
- LoggerD("Retry launch request: %d", retry);
+ 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) {
- 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;
-
- case AUL_R_ECOMM:
- result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Internal IPC error has occurred.",
- ("aul_open_app returns internal IPC error"));
- break;
- }
-
- LogAndReportError(result, &response->get<picojson::object>());
- } else {
- LoggerD("Launch request success");
- ReportSuccess(response->get<picojson::object>());
- }
- };
+ *app_control = app_control_ptr.release();
- launch(response);
- Instance::PostMessage(&this->instance_, response->serialize().c_str());
+ return PlatformResult(ErrorCode::NO_ERROR);
}
+} // namespace
+
void ApplicationManager::LaunchAppControl(const picojson::value& args) {
ScopeLogger();
response_obj.insert(
std::make_pair(kCallbackId, picojson::value(static_cast<double>(callback_id))));
- 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::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>();
- }
-
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 (result.IsError()) {
- LoggerE("Application control to service failed.");
- AsyncResponse(result, &response);
+ auto prepare_app_control_result = PrepareAppControlForLaunchAppControl(args, &app_control);
+ if (prepare_app_control_result.IsError()) {
+ AsyncResponse(LogAndCreateResult(prepare_app_control_result), &response);
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 (!app_id.empty()) {
- LoggerD("app_id: %s", app_id.c_str());
+ if (!launch_app_user_data) {
+ LoggerE("Memory allocation fail!");
+ AsyncResponse(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error."), &response);
+ return;
+ }
- int ret = app_control_set_app_id(app_control_ptr.get(), 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;
- 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)));
+ 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;
}
- }
- 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 (!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;
};
+ }
- 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 = ApplicationUtils::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 =
+ 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");
+ }
+}
- 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 = ApplicationUtils::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.");
+ }
+ }
+
+ *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>());
}
- ReportSuccess(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_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");
+ }
}
// internal impl of app_control_foreach_app_matched() for handling APP_CONTROL_ERROR_APP_NOT_FOUND
app_control_launch_mode_e LaunchModeStringToEnum(const std::string& launch_mode) {
ScopeLogger();
- return launch_mode == kGroupLaunchMode ? APP_CONTROL_LAUNCH_MODE_GROUP : APP_CONTROL_LAUNCH_MODE_SINGLE;
+ return launch_mode == kGroupLaunchMode ? APP_CONTROL_LAUNCH_MODE_GROUP
+ : APP_CONTROL_LAUNCH_MODE_SINGLE;
}
bool LaunchModeIsInvalid(const std::string& launch_mode) {
auto set_field_result = PlatformResult(ErrorCode::UNKNOWN_ERR);
- set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kOperationAppControlField, it_operation);
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kOperationAppControlField, it_operation);
if (set_field_result.IsError()) {
return set_field_result;
}
- set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kURIAppControlField, it_uri);
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kURIAppControlField, it_uri);
if (set_field_result.IsError()) {
return set_field_result;
}
- set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kMIMEAppControlField, it_mime);
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kMIMEAppControlField, it_mime);
if (set_field_result.IsError()) {
return set_field_result;
}
- set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kCategoryAppControlField, it_category);
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kCategoryAppControlField, it_category);
if (set_field_result.IsError()) {
return set_field_result;
}
- set_field_result =
- SetAppControlFieldIfValueSpecified(app_control_tmp, kLaunchModeAppControlField, it_launch_mode);
+ set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kLaunchModeAppControlField,
+ it_launch_mode);
if (set_field_result.IsError()) {
return set_field_result;
}
- set_field_result = SetAppControlFieldIfValueSpecified(app_control_tmp, kDataAppControlField, it_data);
+ set_field_result =
+ SetAppControlFieldIfValueSpecified(app_control_tmp, kDataAppControlField, it_data);
if (set_field_result.IsError()) {
return set_field_result;
}
LoggerE("Get operation failed: %d (%s)", ret, get_error_message(ret));
} else if (tmp_str) {
LoggerD("operation: %s", tmp_str);
- app_control_obj->insert(std::make_pair(kOperationAppControlField, picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kOperationAppControlField, picojson::value(std::string(tmp_str))));
} else {
LoggerD("operation field is empty");
}
LoggerE("Get URI failed: %d (%s)", ret, get_error_message(ret));
} else if (tmp_str) {
LoggerD("URI: %s", tmp_str);
- app_control_obj->insert(std::make_pair(kURIAppControlField, picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kURIAppControlField, picojson::value(std::string(tmp_str))));
} else {
LoggerD("URI field is empty");
}
LoggerE("Get MIME failed: %d (%s)", ret, get_error_message(ret));
} else if (tmp_str) {
LoggerD("MIME: %s", tmp_str);
- app_control_obj->insert(std::make_pair(kMIMEAppControlField, picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kMIMEAppControlField, picojson::value(std::string(tmp_str))));
} else {
LoggerD("MIME field is empty");
}
LoggerE("Get category failed: %d (%s)", ret, get_error_message(ret));
} else if (tmp_str) {
LoggerD("category: %s", tmp_str);
- app_control_obj->insert(std::make_pair(kCategoryAppControlField, picojson::value(std::string(tmp_str))));
+ app_control_obj->insert(
+ std::make_pair(kCategoryAppControlField, picojson::value(std::string(tmp_str))));
} else {
LoggerD("category field is empty");
}
std::string launch_mode_str =
launch_mode == APP_CONTROL_LAUNCH_MODE_SINGLE ? kSingleLaunchMode : kGroupLaunchMode;
LoggerD("launch mode: %s", launch_mode_str.c_str());
- app_control_obj->insert(std::make_pair(kLaunchModeAppControlField, picojson::value(launch_mode_str)));
+ app_control_obj->insert(
+ std::make_pair(kLaunchModeAppControlField, picojson::value(launch_mode_str)));
}
app_control_obj->insert(std::make_pair(kDataAppControlField, picojson::value(picojson::array())));