From 413b911df17e420f85e3bcb19e5fd61f5811374b Mon Sep 17 00:00:00 2001
From: Piotr Kosko
Date: Tue, 7 Mar 2017 12:38:30 +0100
Subject: [PATCH] [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
---
src/common/tools.cc | 120 ++++++++++++++++++++++++++++++++++------------------
1 file changed, 78 insertions(+), 42 deletions(-)
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);
}
--
2.7.4