From: Piotr Kosko Date: Tue, 7 Mar 2017 11:38:30 +0000 (+0100) Subject: [Common] Added cache for mapping privileges X-Git-Tag: accepted/tizen/3.0/common/20170315.122743~3^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=413b911df17e420f85e3bcb19e5fd61f5811374b;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Common] Added cache for mapping privileges [Feature] Mapped privileges are stored in static map and there is no need to connect to database on each call. This would increase the performance of webapi calls, when performed repeatedly. [Verification] Checking privileges works, checked with chrome console. Privilege TCT 100% passrate. Change-Id: Ie25b636412715e2d1678c9d382d923e4be162256 Signed-off-by: Piotr Kosko --- diff --git a/src/common/tools.cc b/src/common/tools.cc index 8a6a3d3..638352f 100644 --- a/src/common/tools.cc +++ b/src/common/tools.cc @@ -266,6 +266,13 @@ PlatformResult CheckAccess(const std::string& privilege) { PlatformResult CheckAccess(const std::vector& privileges) { LoggerD("Enter"); + // Local cache of mapped privilege strings. This routine can be called many times, especially + // during application launch, generating a high overhead of retrieving mapped privileges from + // the underlying databases. This is especially the case since the same mappings can end up + // being retrieved several times. + using MappedPrivilegeCache = std::map>; + static MappedPrivilegeCache mapped_privilege_cache; + std::string api_version; PlatformResult res = common::tools::GetPkgApiVersion(&api_version); if (res.IsError()) { @@ -283,30 +290,45 @@ PlatformResult CheckAccess(const std::vector& privileges) { g_list_free(mapped_glist); }; - input_glist = g_list_append(input_glist, (void*)input_priv.c_str()); - int ret = privilege_manager_get_mapped_privilege_list(api_version.c_str(), - PRVMGR_PACKAGE_TYPE_WRT, - input_glist, - &mapped_glist); - if (ret != PRVMGR_ERR_NONE) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get mapped privilege list"); - } - - LoggerD("Mapped privileges:"); - std::vector mapped_vector; - auto push_elem = [](gpointer data, gpointer user_data) -> void { - if (data && user_data) { - std::vector* mapped_vector = - static_cast*>(user_data); - char* char_data = static_cast(data); - mapped_vector->push_back(char_data); - LoggerD("mapped to: %s", char_data); + std::vector* mapped_vector_ptr = nullptr; + + // Check if mapped privilege is in local cache first + MappedPrivilegeCache::const_iterator it = mapped_privilege_cache.find(input_priv); + if (mapped_privilege_cache.end() == it) { + LoggerD("Mapped privileges - need to be fetched from database"); + // Not in cache - retrieve from underlying databases. + input_glist = g_list_append(input_glist, (void*)input_priv.c_str()); + int ret = privilege_manager_get_mapped_privilege_list(api_version.c_str(), + PRVMGR_PACKAGE_TYPE_WRT, + input_glist, + &mapped_glist); + if (PRVMGR_ERR_NONE != ret) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get mapped privilege list"); } - }; - g_list_foreach (mapped_glist, push_elem, &mapped_vector); - if (!AccessControl::GetInstance().CheckAccess(mapped_vector)){ - for (const auto& mapped_priv : mapped_vector) { + // initialize empty cache vector + mapped_privilege_cache[input_priv] = std::vector(); + LoggerD("Mapped privileges:"); + auto push_elem = [](gpointer data, gpointer user_data) -> void { + if (data && user_data) { + std::vector* mapped_vector = + static_cast*>(user_data); + char* char_data = static_cast(data); + mapped_vector->push_back(char_data); + LoggerD("mapped to: %s", char_data); + } + }; + // fill the vector with data + g_list_foreach (mapped_glist, push_elem, &mapped_privilege_cache[input_priv]); + mapped_vector_ptr = &mapped_privilege_cache[input_priv]; + } else { + // Retrieve from local cache + LoggerD("Mapped privileges already in cache"); + mapped_vector_ptr = (std::vector*) &(it->second); + } + + if (!AccessControl::GetInstance().CheckAccess(*mapped_vector_ptr)){ + for (const auto& mapped_priv : *mapped_vector_ptr) { LoggerD("Access to privilege: %s has been denied.", mapped_priv.c_str()); } return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied"); @@ -318,6 +340,12 @@ PlatformResult CheckAccess(const std::vector& privileges) { PlatformResult GetPkgApiVersion(std::string* api_version) { LoggerD("Entered"); + // Local cache of API version string. This can be expensive to retrieve from + // underlying databases and this routine can be called many times during + // application launch. + static std::string cached_api_version; + static int cached_pid = -1; + char* app_id = nullptr; char* pkgid = nullptr; char* api_ver = nullptr; @@ -340,32 +368,40 @@ PlatformResult GetPkgApiVersion(std::string* api_version) { }; pid_t pid = getpid(); - int ret = app_manager_get_app_id(pid, &app_id); - if (ret != APP_MANAGER_ERROR_NONE) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app id"); - } + if (cached_pid == pid) { + *api_version = cached_api_version; // Retrieve from local cache + } else { + int ret = app_manager_get_app_id(pid, &app_id); + if (ret != APP_MANAGER_ERROR_NONE) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app id"); + } - ret = app_info_create(app_id, &app_handle); - if (ret != APP_MANAGER_ERROR_NONE) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app info"); - } + ret = app_info_create(app_id, &app_handle); + if (ret != APP_MANAGER_ERROR_NONE) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get app info"); + } - ret = app_info_get_package(app_handle, &pkgid); - if ((ret != APP_MANAGER_ERROR_NONE) || (pkgid == nullptr)) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkg id"); - } + ret = app_info_get_package(app_handle, &pkgid); + if ((ret != APP_MANAGER_ERROR_NONE) || (pkgid == nullptr)) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkg id"); + } - ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, getuid(), &pkginfo_handle); - if (ret != PMINFO_R_OK) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkginfo_h"); - } + ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, getuid(), &pkginfo_handle); + if (ret != PMINFO_R_OK) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get pkginfo_h"); + } + + ret = pkgmgrinfo_pkginfo_get_api_version(pkginfo_handle, &api_ver); + if (ret != PMINFO_R_OK) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get api version"); + } + + cached_api_version = api_ver; // Save in local cache + cached_pid = pid; - ret = pkgmgrinfo_pkginfo_get_api_version(pkginfo_handle, &api_ver); - if (ret != PMINFO_R_OK) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Fail to get api version"); + *api_version = api_ver; } - *api_version = api_ver; return PlatformResult(ErrorCode::NO_ERROR); }