#include "application_manager.h"
+#include <sys/stat.h>
#include <unistd.h>
+#include <thread>
#include <type_traits>
#include <app_control_internal.h>
{SYSTEM_EVENT_DATA_ROAMING_STATE, EVENT_KEY_DATA_ROAMING_STATE},
{SYSTEM_EVENT_FONT_SET, EVENT_KEY_FONT_SET}};
-#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE) || defined(TIZEN_COMMON)
const int kMaximumBatteryRetrievedObjects = 30;
const int kMaximumAppsRetrievedObjects = 10;
const int kDefaultPeriodOfTime = 30;
#endif
}
+std::set<LaunchAppControlCallbackData*> ApplicationManager::launch_app_control_set_global_{};
+std::mutex ApplicationManager::launch_app_control_set_mutex_{};
+
ApplicationManager::ApplicationManager(ApplicationInstance& instance)
: pkgmgr_client_handle_(nullptr),
pkgmgr_client_uninstall_handle_(nullptr),
LoggerE("app_manager_event_destroy failed, error: %d", ret);
}
}
+
+ // 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.
+ std::lock_guard<std::mutex> lock(launch_app_control_set_mutex_);
+ 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);
+ });
}
void ApplicationManager::GetCurrentApplication(const std::string& app_id, picojson::object* out) {
picojson::value app_info = picojson::value(picojson::object());
picojson::object& app_info_obj = app_info.get<picojson::object>();
- ApplicationUtils::CreateApplicationInformation(handle, &app_info_obj);
+ utils::CreateApplicationInformation(handle, &app_info_obj);
pkgmgrinfo_appinfo_destroy_appinfo(handle);
picojson::value result = picojson::value(picojson::object());
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);
+ auto result = utils::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);
reply_callback_id = reply.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* launch_app_user_data = new (std::nothrow)
LaunchAppControlCallbackData{&this->instance_, response, reply_callback_id};
if (!launch_app_user_data) {
LaunchAppControlCallbackData* callback_data =
static_cast<LaunchAppControlCallbackData*>(user_data);
- if (!callback_data) {
- LoggerD("reply_callback failed: user_data is nullptr");
+
+ 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;
}
if (APP_CONTROL_RESULT_SUCCEEDED == result) {
LoggerD("App started");
return_value_obj.insert(std::make_pair("data", picojson::value(picojson::array())));
- if (!ApplicationUtils::ServiceToApplicationControlDataArray(
+ if (!utils::ServiceToApplicationControlDataArray(
reply, &return_value_obj.find("data")->second.get<picojson::array>())) {
return_value_obj.erase("data");
}
}
Instance::PostMessage(callback_data->instance, return_value.serialize().c_str());
- delete callback_data;
+ // 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
};
}
LaunchAppControlCallbackData* callback_data =
static_cast<LaunchAppControlCallbackData*>(user_data);
- auto result = ApplicationUtils::TranslateAppControlError(launch_result);
+ 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;
+ }
+
+ auto result = utils::TranslateAppControlError(launch_result);
if (result.IsError()) {
LogAndReportError(result, &(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;
- }
+ // 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
};
/*
* 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(
+ 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");
+ // 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,
+ // 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_);
+ launch_app_control_set_.insert(launch_app_user_data);
+ launch_app_control_set_global_.insert(launch_app_user_data);
+ LoggerD("App launched, data %p stored for later release", launch_app_user_data);
}
}
-
namespace {
PlatformResult TranslateLaunchError(app_control_error_e return_code) {
ScopeLogger();
- auto result = ApplicationUtils::TranslateAppControlError(return_code);
+ auto result = utils::TranslateAppControlError(return_code);
if (ErrorCode::SECURITY_ERR == result.error_code()) {
result = PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error.");
}
};
/*
- * TODO: Observe how often app_control_send_launch_request_async tries to launch the application.
+ * TODO: Observe how often app_control_send_resume_request 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.
+ * New implementation, using app_control_send_resume_request 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)));
+ 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;
const picojson::object& app_control_obj = control.get<picojson::object>();
app_control_h app_control = nullptr;
- result = ApplicationUtils::ApplicationControlToService(app_control_obj, &app_control);
+ result = utils::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
picojson::array* array = static_cast<picojson::array*>(user_data);
array->push_back(picojson::value(picojson::object()));
- ApplicationUtils::CreateApplicationInformation(handle,
- &array->back().get<picojson::object>());
+ utils::CreateApplicationInformation(handle, &array->back().get<picojson::object>());
pkgmgrinfo_appinfo_destroy_appinfo(handle);
}
picojson::array* array = static_cast<picojson::array*>(user_data);
array->push_back(picojson::value(picojson::object()));
- if (!ApplicationUtils::CreateApplicationContext(app_context,
- &array->back().get<picojson::object>())) {
+ if (!utils::CreateApplicationContext(app_context, &array->back().get<picojson::object>())) {
array->pop_back();
return false;
}
}
picojson::value result = picojson::value(picojson::object());
- ApplicationUtils::CreateApplicationContext(pid, app_id, &result.get<picojson::object>());
+ utils::CreateApplicationContext(pid, app_id, &result.get<picojson::object>());
ReportSuccess(result, *out);
}
picojson::array* array = static_cast<picojson::array*>(user_data);
array->push_back(picojson::value(picojson::object()));
- ApplicationUtils::CreateApplicationInformation(handle,
- &array->back().get<picojson::object>());
+ utils::CreateApplicationInformation(handle, &array->back().get<picojson::object>());
return 0;
};
}
picojson::value result = picojson::value(picojson::object());
- ApplicationUtils::CreateApplicationInformation(handle, &result.get<picojson::object>());
+ utils::CreateApplicationInformation(handle, &result.get<picojson::object>());
pkgmgrinfo_appinfo_destroy_appinfo(handle);
ReportSuccess(result, *out);
picojson::array* array = static_cast<picojson::array*>(user_data);
array->push_back(picojson::value(picojson::object()));
- ApplicationUtils::CreateApplicationCertificate(cert_name, cert_value,
- &array->back().get<picojson::object>());
+ utils::CreateApplicationCertificate(cert_name, cert_value,
+ &array->back().get<picojson::object>());
return true;
};
void ApplicationManager::GetAppSharedUri(const std::string& app_id, picojson::object* out) {
ScopeLogger();
+ // this implementation assumes that shared/trusted path is the obligatory member of application
+ // and it is used to extract the parent directory 'shared'
+ char* path = nullptr;
+ int ret = app_manager_get_shared_trusted_path(app_id.c_str(), &path);
+ if (APP_MANAGER_ERROR_NONE != ret) {
+ // if the application does not exist, there is no need to check "res" directory
+ if (APP_MANAGER_ERROR_NO_SUCH_APP == ret) {
+ LogAndReportError(PlatformResult(ErrorCode::NOT_FOUND_ERR, "Failed to get shared URI."), out);
+ return;
+ }
- char* package_id = nullptr;
-
- package_id = GetPackageId(app_id);
- // automatically release the memory
- std::unique_ptr<char, void (*)(void*)> package_id_ptr(package_id, &std::free);
-
- if (!package_id) {
- LogAndReportError(PlatformResult(ErrorCode::NOT_FOUND_ERR, "Failed to get package."), out);
- return;
+ // if the shared_trusted directory is not properly returned, gathering the shared/res path,
+ // which is the obligatory member. The global path could be different then:
+ // e.g. instead of path: /opt/usr/home/owner/apps_rw/org.example.basic/shared/
+ // returned path is: /opt/usr/globalapps/org.example.basic/shared/
+ LoggerW(
+ "app_manager_get_shared_trusted_path failed(), trying "
+ "app_manager_get_shared_resource_path() to gather path");
+ int ret = app_manager_get_shared_resource_path(app_id.c_str(), &path);
+ if (APP_MANAGER_ERROR_NONE != ret) {
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get shared URI."), out);
+ return;
+ }
}
- pkgmgrinfo_pkginfo_h pkg_info = nullptr;
-
- int ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(package_id, getuid(), &pkg_info);
- std::unique_ptr<std::remove_pointer<pkgmgrinfo_pkginfo_h>::type, int (*)(pkgmgrinfo_pkginfo_h)>
- pkg_info_ptr(pkg_info,
- &pkgmgrinfo_pkginfo_destroy_pkginfo); // automatically release the memory
-
- if (PMINFO_R_OK != ret) {
- LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get package info."), out,
- ("Failed to get package info: %d (%s)", ret, get_error_message(ret)));
- return;
- }
+ std::string path_str = path;
+ free(path);
- char* root_path = nullptr;
- ret = pkgmgrinfo_pkginfo_get_root_path(pkg_info, &root_path);
+ std::string shared_path = path_str.substr(0, path_str.rfind("/", path_str.length() - 2));
- if (PMINFO_R_OK != ret || nullptr == root_path) {
- LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get root path."), out,
- ("Failed to get root path: %d (%s)", ret, get_error_message(ret)));
+ // checking if path is valid
+ struct stat stat_res;
+ if (0 != stat(shared_path.c_str(), &stat_res)) {
+ LoggerW("Path %s does not exist", shared_path.c_str());
+ LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get shared URI."), out);
return;
}
- picojson::value result = picojson::value(kTizenApisFileScheme + root_path + kTizenApisAppSlash +
- kTizenApisAppShared + kTizenApisAppSlash);
+ picojson::value result = picojson::value(kTizenApisFileScheme + shared_path);
ReportSuccess(result, *out);
}
-#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE) || defined(TIZEN_COMMON)
PlatformResult ApplicationManager::BatteryUsageFilter(const picojson::value& args,
const context_history_filter_h filter,
context_history_data_e* data_type_out) {
void ApplicationManager::GetBatteryUsageInfo(const picojson::value& args, picojson::object* out) {
ScopeLogger();
-#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE) || defined(TIZEN_COMMON)
int callback_id = -1;
const auto& callback = args.get(kCallbackId);
if (callback.is<double>()) {
void ApplicationManager::GetAppsUsageInfo(const picojson::value& args, picojson::object* out) {
ScopeLogger();
-#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE) || defined(TIZEN_COMMON)
int callback_id = static_cast<int>(args.get(kCallbackId).get<double>());
auto get_apps_usage = [args](const std::shared_ptr<picojson::value>& response) -> void {
picojson::array* array = static_cast<picojson::array*>(user_data);
array->push_back(picojson::value(picojson::object()));
- ApplicationUtils::CreateApplicationMetaData(meta_key, meta_value,
- &array->back().get<picojson::object>());
+ utils::CreateApplicationMetaData(meta_key, meta_value, &array->back().get<picojson::object>());
return 0;
};
continue;
}
auto info = data_obj.insert(std::make_pair(kData, picojson::value(picojson::object())));
- ApplicationUtils::CreateApplicationInformation(
- handle, &info.first->second.get<picojson::object>());
+ utils::CreateApplicationInformation(handle, &info.first->second.get<picojson::object>());
pkgmgrinfo_appinfo_destroy_appinfo(handle);
} break;
case Event::kUninstalled:
return;
}
- ret = package_info_foreach_app_from_package(package_info, PACKAGE_INFO_ALLAPP,
+ ret = package_info_foreach_app_from_package(package_info, PACKAGE_INFO_APP_COMPONENT_TYPE_ALL,
ApplicationIdCallback, this);
if (PACKAGE_MANAGER_ERROR_NONE != ret) {
LoggerE("Failed to get application IDs: %d (%s)", ret, get_error_message(ret));
manager->status_callback_(&event);
}
-#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
+#if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE) || defined(TIZEN_COMMON)
PlatformResult ApplicationManager::GetContextHistory(
const picojson::value& args, picojson::object* out,
common::PlatformResult (*modify_filter_cb)(const picojson::value&,