// Calling order of reply_callback and result_callback of launchAppControl
// cannot be determined, reply_callback depends on application scenario, which
// cannot be predicted. Moreover reply_callback is optional and can be called or not,
- // thus callback_data is relesed here at the end of application lifetime.
+ // thus pending callback_data is relesed here at the end of application lifetime.
std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
+ LoggerD("Releasing pending handles");
std::for_each(launch_app_control_set_.begin(), launch_app_control_set_.end(),
[](LaunchAppControlCallbackData* const& data) {
LoggerD("Releasing callback data: %p", data);
delete data;
launch_app_control_set_global_.erase(data);
});
+ LoggerD("Pending LaunchAppControlCallbackData - this instance: %u, globally: %u", launch_app_control_set_.size(), launch_app_control_set_global_.size());
}
void ApplicationManager::GetCurrentApplication(const std::string& app_id, picojson::object* out) {
} // namespace
+void ApplicationManager::TryRelease(LaunchAppControlCallbackData* callback_data) {
+ if (0 == --callback_data->reference_count) {
+ LoggerD("Releasing callback_data: %p", callback_data);
+ std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
+ launch_app_control_set_global_.erase(callback_data);
+ callback_data->manager->launch_app_control_set_.erase(callback_data);
+ delete callback_data;
+ } else {
+ LoggerD("NOT Releasing callback_data: %p, only decremented reference count to: %u", callback_data, callback_data->reference_count);
+ LoggerD("Pending LaunchAppControlCallbackData - this instance: %u, globally: %u", callback_data->manager->launch_app_control_set_.size(), launch_app_control_set_global_.size());
+ }
+}
+
void ApplicationManager::LaunchAppControl(const picojson::value& args) {
ScopeLogger();
}
LaunchAppControlCallbackData* launch_app_user_data = new (std::nothrow)
- LaunchAppControlCallbackData{&this->instance_, response, reply_callback_id};
+ LaunchAppControlCallbackData{&this->instance_, this, response, reply_callback_id, 1};
if (!launch_app_user_data) {
LoggerE("Memory allocation fail!");
app_control_reply_cb reply_callback = nullptr;
if (!reply_callback_id.empty()) {
launch_app_user_data->reply_callback_id = reply_callback_id;
+ // reply_callback depends on application scenario, which cannot be predicted,
+ // moreover reply_callback is optional and can be called or not.
+ // If Web API user define reply callback, we assume that callee application will
+ // send reply callback to caller and cause proper data release, otherwise there will
+ // be leak of memory.
+ launch_app_user_data->reference_count++;
reply_callback = [](app_control_h request, app_control_h reply, app_control_result_e result,
void* user_data) {
LaunchAppControlCallbackData* callback_data =
static_cast<LaunchAppControlCallbackData*>(user_data);
- std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
- if (!launch_app_control_set_global_.count(callback_data)) {
- LoggerE("Invalid callback_data: %p", callback_data);
- return;
+ {
+ std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
+ if (!launch_app_control_set_global_.count(callback_data)) {
+ LoggerE("Callback data: %p refers to already released instance", callback_data);
+ // Not releasing callback_data here - it was already released in destructor
+ return;
+ }
}
picojson::value return_value = picojson::value(picojson::object());
}
Instance::PostMessage(callback_data->instance, return_value.serialize().c_str());
- // Calling order of reply_callback and result_callback cannot be determined,
- // thus callback_data is not released here, but stored for release in destructor of
- // ApplicationManager
+ TryRelease(callback_data);
};
}
LaunchAppControlCallbackData* callback_data =
static_cast<LaunchAppControlCallbackData*>(user_data);
- std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
- if (!launch_app_control_set_global_.count(callback_data)) {
- LoggerE("Invalid callback_data: %p", callback_data);
- return;
+ {
+ std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
+ if (!launch_app_control_set_global_.count(callback_data)) {
+ LoggerE("Callback data: %p refers to already released instance", callback_data);
+ // Not releasing callback_data here - it was already released in destructor
+ return;
+ }
}
auto result = utils::TranslateAppControlError(launch_result);
Instance::PostMessage(callback_data->instance, callback_data->response->serialize().c_str());
- // Calling order of reply_callback and result_callback cannot be determined,
- // thus callback_data is not released here, but stored for release in destructor of
- // ApplicationManager
+ TryRelease(callback_data);
};
/*
delete launch_app_user_data;
AsyncResponse(launch_result, &response);
} else {
- // Calling order of reply_callback and result_callback cannot be determined,
- // reply_callback depends on application scenario, which cannot be predicted.
- // Moreover reply_callback is optional and can be called or not,
- // thus callback_data is stored for releasing in destructor of ApplicationManager
- // at the end of application lifetime.
- // We can not be sure whether callbach will not fire after instance destruction,
+ // reply_callback depends on application scenario, which cannot be predicted,
+ // moreover reply_callback is optional and can be called or not.
+ // If Web API user define reply callback, we assume that callee application will
+ // send reply callback to caller and cause proper data release, otherwise there will
+ // be leak of memory.
+ // We can not be sure whether callback will not fire after instance destruction,
// we store all user_data pointers in static launch_app_control_set_global_ to check
// if they are still valid.
std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
namespace application {
class ApplicationInstance;
+class ApplicationManager;
typedef struct LaunchAppControlCallbackDataStruct {
ApplicationInstance* instance;
+ ApplicationManager* manager;
std::shared_ptr<picojson::value> response;
std::string reply_callback_id;
+ // reference_count is used for determining the data release time, as reply_callback is optional,
+ // reference_count is by default equal to 1, but in case if WebAPI user register reply_callback,
+ // then it is incremented. Data release design assumes that the data is released after all callbacks
+ // are executed and reference count is decreased to 0.
+ size_t reference_count;
} LaunchAppControlCallbackData;
class ApplicationManager {
// callback is fired after ApplicationInstance destruction
static std::set<LaunchAppControlCallbackData*> launch_app_control_set_global_;
static std::mutex launch_app_control_set_mutex_;
+ static void TryRelease(LaunchAppControlCallbackData* callback_data);
static void OnEvent(const char* event_name, bundle* event_data, void* user_data);
static void OnStatusEvent(const char* type, const char* app_id,
app_manager_event_type_e event_type,