Fix to wrong free filter list
[platform/core/appfw/pkgmgr-info.git] / src / server / database / db_handle_provider.cc
index bd3d6e0..fb14e54 100644 (file)
@@ -100,7 +100,7 @@ std::string DBHandleProvider::global_parser_filedb_path_;
 std::string DBHandleProvider::cert_filedb_path_;
 std::unordered_set<pid_t> DBHandleProvider::writer_pid_list_;
 std::recursive_mutex DBHandleProvider::lock_;
-std::mutex DBHandleProvider::pid_list_lock_;
+std::shared_mutex DBHandleProvider::pid_list_lock_;
 
 DBHandleProvider::DBHandleProvider(uid_t uid)
     : uid_(uid),
@@ -130,10 +130,16 @@ DBHandleProvider::DBHandleProvider(uid_t uid)
 }
 
 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
-  static std::mutex singleton_lock_;
-  std::unique_lock<std::mutex> u(singleton_lock_);
+  static std::shared_mutex singleton_lock_;
+  std::shared_lock<std::shared_mutex> s(singleton_lock_);
 
   uid = ConvertUID(uid);
+  auto it = provider_map_.find(uid);
+  if (it != provider_map_.end())
+    return *(it->second);
+
+  s.unlock();
+  std::unique_lock<std::shared_mutex> u(singleton_lock_);
   auto& prov = provider_map_[uid];
   if (prov == nullptr)
     prov.reset(new DBHandleProvider(uid));
@@ -142,7 +148,7 @@ DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
 }
 
 bool DBHandleProvider::IsCrashedWriteRequest() {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
 
   if (writer_pid_list_.empty())
     return false;
@@ -290,13 +296,11 @@ void DBHandleProvider::UnsetMemoryMode(pid_t pid) {
   is_user_memdb_set_ = false;
   is_global_memdb_set_ = false;
 
-  TrimCache();
-
   LOG(DEBUG) << "Set Memory mode : File";
 }
 
 bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
   if (!is_user_memdb_set_)
     return false;
 
@@ -321,13 +325,15 @@ void DBHandleProvider::ReleaseCache() {
 
   app_map_.clear();
   pkg_map_.clear();
+  pending_pkg_.clear();
+  pkg_app_map_.clear();
   CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
 
   released_ = true;
 }
 
 bool DBHandleProvider::IsWriter(pid_t pid) {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> s(pid_list_lock_);
   return writer_pid_list_.find(pid) != writer_pid_list_.end();
 }
 
@@ -335,12 +341,8 @@ int DBHandleProvider::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write,
     const std::string& locale) {
   pkg_map_.clear();
   app_map_.clear();
-
-  GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal);
-  if (list == nullptr) {
-    LOG(ERROR) << "Out of memory";
-    return PMINFO_R_ERROR;
-  }
+  pending_pkg_.clear();
+  pkg_app_map_.clear();
 
   const char* dbpath = sqlite3_db_filename(db, "main");
   bool is_inmemory_db = false;
@@ -354,7 +356,14 @@ int DBHandleProvider::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write,
   if (!is_inmemory_db && !GetModifiedTime(dbpath, &start_time))
     return PMINFO_R_ERROR;
 
+  GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal);
+  if (list == nullptr) {
+    LOG(ERROR) << "Out of memory";
+    return PMINFO_R_ERROR;
+  }
+
   pkgmgrinfo_filter_x tmp_filter = { 0, };
+  tmp_filter.cache_flag = true;
   int ret = pkginfo_internal_filter_get_list(db, &tmp_filter, uid_,
                                              locale.c_str(), list);
   if (ret == PMINFO_R_OK) {
@@ -396,12 +405,13 @@ int DBHandleProvider::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write,
 
   if (ret == PMINFO_R_OK) {
     for (auto& app : app_list) {
-      if (pkg_map_.find(app->package) == pkg_map_.end()) {
+      auto it = pkg_map_.find(app->package);
+      if (it == pkg_map_.end()) {
         LOG(ERROR) << "Can not find package from pkg_map";
         return PMINFO_R_ERROR;
       }
 
-      app->privileges = pkg_map_[app->package].front()->privileges;
+      app->privileges = it->second->privileges;
       std::string appid = app->appid;
       AddApplication(std::move(appid), std::move(app));
     }
@@ -412,23 +422,40 @@ int DBHandleProvider::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write,
   return ret;
 }
 
+inline bool CheckPkgFilters(pkgmgrinfo_filter_x* filter,
+    const std::shared_ptr<package_x>& info) {
+  for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
+    auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
+    auto* checker = FilterCheckerProvider::GetInst().
+        GetPkgFilterChecker(node->prop);
+    if (!checker->CheckFilter(node, info.get()))
+      return false;
+  }
+
+  return true;
+}
+
 std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
-    pid_t pid, bool write, pkgmgrinfo_filter_x* filter,
+    pid_t pid, pkgmgrinfo_filter_x* filter,
     const std::string& package) {
   std::vector<std::shared_ptr<package_x>> ret;
-  for (auto& info : pkg_map_[package]) {
-    bool pass = true;
-    for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
-      auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
-      auto* checker = FilterCheckerProvider::GetInst().
-          GetPkgFilterChecker(node->prop);
-      if (!checker->CheckFilter(node, info.get())) {
-        pass = false;
-        break;
-      }
+
+  if (__check_package_storage_status(filter)) {
+    if (pkgmgrinfo_pkginfo_filter_add_bool(filter,
+        PMINFO_PKGINFO_PROP_PACKAGE_CHECK_STORAGE, true) != PMINFO_R_OK) {
+      LOG(ERROR) << "Fail to add check storage value to filter";
+      return {};
+    }
+  }
+  if (package.empty()) {
+    for (auto& info : pkg_map_) {
+      if (CheckPkgFilters(filter, info.second))
+        ret.push_back(info.second);
     }
-    if (pass)
-      ret.push_back(info);
+  } else {
+    auto map_it = pkg_map_.find(package);
+    if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second))
+      ret.push_back(map_it->second);
   }
 
   return ret;
@@ -436,38 +463,21 @@ std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
 
 void DBHandleProvider::AddPackage(std::string package, package_x* info) {
   auto ptr = std::shared_ptr<package_x>(info, pkgmgrinfo_basic_free_package);
-  pkg_map_[package].push_back(ptr);
-  pkg_map_[""].push_back(std::move(ptr));
+  pkg_map_[package] = std::move(ptr);
 }
 
-std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
-    pid_t pid, bool write, pkgmgrinfo_filter_x* filter,
-    const std::string& app) {
-  /* make metadata filter map */
-  std::unordered_map<std::string, std::string> metadata_map;
-  for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
-    auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
-    if (node->key == nullptr)
-      continue;
-
-    metadata_map[node->key] = (node->value ? node->value : "");
-  }
-
-  std::vector<std::shared_ptr<application_x>> ret;
-  for (auto& info : app_map_[app]) {
-    bool pass = true;
+inline bool CheckAppFilters(pkgmgrinfo_filter_x* filter,
+    const std::shared_ptr<application_x>& info,
+    const std::unordered_map<std::string, std::string>& metadata_map) {
     for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
       auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
       auto* checker = FilterCheckerProvider::GetInst().
           GetAppFilterChecker(node->prop);
-      if (!checker->CheckFilter(node, info.get())) {
-        pass = false;
-        break;
-      }
+      if (!checker->CheckFilter(node, info.get()))
+        return false;
     }
-    if (!pass)
-      continue;
 
+    bool pass = true;
     if (!metadata_map.empty()) {
       pass = false;
       for (auto* it = info->metadata; it != nullptr; it = g_list_next(it)) {
@@ -479,36 +489,260 @@ std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
 
           if (metadata->second.empty() ||
               strcmp(node->value ? node->value : "",
-                  metadata->second.c_str()) == 0) {
-            pass = true;
-            break;
-          }
+                  metadata->second.c_str()) == 0)
+            return true;
         }
       }
     }
 
-    if (pass)
-      ret.push_back(info);
+    return pass;
+}
+
+std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
+    pid_t pid, pkgmgrinfo_filter_x* filter,
+    const std::string& app) {
+  /* make metadata filter map */
+  std::unordered_map<std::string, std::string> metadata_map;
+  for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
+    auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
+    if (node->key == nullptr)
+      continue;
+
+    metadata_map[node->key] = (node->value ? node->value : "");
+  }
+
+  std::vector<std::shared_ptr<application_x>> ret;
+  if (pkgmgr_server::internal::check_app_storage_status(filter)) {
+    if (pkgmgrinfo_appinfo_filter_add_bool(filter,
+        PMINFO_APPINFO_PROP_APP_CHECK_STORAGE, true) != PMINFO_R_OK) {
+      LOG(ERROR) << "Fail to add check storage value to filter";
+      return {};
+    }
+  }
+
+  if (app.empty()) {
+    for (auto& info : app_map_) {
+      if (CheckAppFilters(filter, info.second, metadata_map))
+        ret.push_back(info.second);
+    }
+  } else {
+    auto map_it = app_map_.find(app);
+    if (map_it != app_map_.end() &&
+        CheckAppFilters(filter, map_it->second, metadata_map))
+      ret.push_back(map_it->second);
   }
+
   return ret;
 }
 
-void DBHandleProvider::AddApplication(std::string app, std::shared_ptr<application_x> info) {
-  app_map_[app].push_back(info);
-  app_map_[""].push_back(std::move(info));
+void DBHandleProvider::AddApplication(std::string app,
+    std::shared_ptr<application_x> info) {
+  pkg_app_map_[info->package].emplace(app);
+  app_map_[app] = std::move(info);
 }
 
 void DBHandleProvider::InsertPID(pid_t pid) {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
 
   writer_pid_list_.insert(pid);
 }
 
 bool DBHandleProvider::ErasePID(pid_t pid) {
-  std::unique_lock<std::mutex> u(pid_list_lock_);
+  std::unique_lock<std::shared_mutex> u(pid_list_lock_);
 
   return writer_pid_list_.erase(pid) == 1;
 }
 
+void DBHandleProvider::RegisterPendingPackageInfo(
+    package_x* info, pid_t pid) {
+  if (!info || !info->package)
+    return;
+
+  pending_pkg_[pid].emplace(info->package);
+}
+
+bool DBHandleProvider::UpdatePendingPackageInfo(sqlite3* db,
+    pid_t pid, uid_t uid, const std::string& locale) {
+  auto it = pending_pkg_.find(pid);
+  if (it == pending_pkg_.end()) {
+    LOG(WARNING) << "There is no package that is pending by the pid : " << pid;
+    return true;
+  }
+
+  GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal);
+  if (list == nullptr) {
+    LOG(ERROR) << "Out of memory";
+    return false;
+  }
+
+  pkgmgrinfo_filter_x tmp_filter = { 0, };
+  pkgmgrinfo_node_x node = {
+    .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID
+  };
+  tmp_filter.cache_flag = true;
+  tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
+  for (const auto& pkg : it->second) {
+    pkg_map_.erase(pkg);
+    for (auto& appid : pkg_app_map_[pkg]) {
+      app_map_.erase(appid);
+    }
+
+    pkg_app_map_.erase(pkg);
+    node.value = const_cast<char*>(pkg.c_str());
+    pkginfo_internal_filter_get_list(db, &tmp_filter,
+        uid_, locale.c_str(), list);
+  }
+
+  GHashTableIter iter;
+  gpointer value;
+  g_hash_table_iter_init(&iter, list);
+  while (g_hash_table_iter_next(&iter, nullptr, &value)) {
+    auto* pkg = reinterpret_cast<package_x*>(value);
+    std::string pkgid = pkg->package;
+    AddPackage(std::move(pkgid), pkg);
+  }
+
+  g_hash_table_iter_init(&iter, list);
+  node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
+  while (g_hash_table_iter_next(&iter, nullptr, &value)) {
+    auto* pkg = reinterpret_cast<package_x*>(value);
+    node.value = pkg->package;
+    std::vector<std::shared_ptr<application_x>> app_list;
+    pkgmgr_server::internal::appinfo_internal_filter_get_list(
+        db, &tmp_filter, uid_, uid, locale.c_str(), app_list);
+
+    for (auto& app : app_list) {
+      app->privileges = pkg->privileges;
+      std::string appid = app->appid;
+      AddApplication(std::move(appid), std::move(app));
+    }
+  }
+
+  g_hash_table_destroy(list);
+  g_slist_free(tmp_filter.list);
+  pending_pkg_.erase(pid);
+  return true;
+}
+
+bool DBHandleProvider::UpdateCachePkg(sqlite3* db, uid_t uid,
+    const std::string& pkgid, const std::string& locale) {
+  GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal);
+  if (list == nullptr) {
+    LOG(ERROR) << "Out of memory";
+    return false;
+  }
+
+  pkgmgrinfo_filter_x tmp_filter = { 0, };
+  pkgmgrinfo_node_x node = {
+    .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID,
+    .value = const_cast<char*>(pkgid.c_str())
+  };
+  tmp_filter.cache_flag = true;
+  tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
+  pkginfo_internal_filter_get_list(db, &tmp_filter,
+      uid_, locale.c_str(), list);
+
+  GHashTableIter iter;
+  gpointer value;
+  g_hash_table_iter_init(&iter, list);
+  while (g_hash_table_iter_next(&iter, nullptr, &value)) {
+    auto* pkg = reinterpret_cast<package_x*>(value);
+    std::string pkgid = pkg->package;
+    AddPackage(pkgid, pkg);
+
+    for (auto& appid : pkg_app_map_[pkgid]) {
+      app_map_.erase(appid);
+    }
+
+    pkg_app_map_.erase(pkgid);
+
+    std::vector<std::shared_ptr<application_x>> app_list;
+    node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
+    node.value = const_cast<char*>(pkgid.c_str());
+
+    pkgmgr_server::internal::appinfo_internal_filter_get_list(
+        db, &tmp_filter, uid_, uid, locale.c_str(), app_list);
+
+    for (auto& app : app_list) {
+      app->privileges = pkg->privileges;
+      std::string appid = app->appid;
+      AddApplication(std::move(appid), std::move(app));
+    }
+  }
+
+  g_hash_table_destroy(list);
+  g_slist_free(tmp_filter.list);
+  return true;
+}
+
+bool DBHandleProvider::UpdateCacheApp(sqlite3* db, uid_t uid,
+    const std::string& appid, const std::string& locale) {
+  pkgmgrinfo_filter_x tmp_filter = { 0, };
+  pkgmgrinfo_node_x node = {
+    .prop = E_PMINFO_APPINFO_PROP_APP_ID,
+    .value = const_cast<char*>(appid.c_str())
+  };
+  tmp_filter.cache_flag = true;
+  tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
+
+  std::vector<std::shared_ptr<application_x>> app_list;
+  app_map_.erase(appid);
+  pkgmgr_server::internal::appinfo_internal_filter_get_list(db,
+      &tmp_filter, uid_, uid, locale.c_str(), app_list);
+  g_slist_free(tmp_filter.list);
+
+  for (auto& app : app_list) {
+    auto it = pkg_map_.find(app->package);
+    if (it == pkg_map_.end()) {
+      LOG(ERROR) << "Can not find package from pkg_map";
+      return false;
+    }
+
+    pkg_app_map_[app->package].erase(app->appid);
+    app->privileges = it->second->privileges;
+    std::string appid = app->appid;
+    AddApplication(std::move(appid), std::move(app));
+  }
+
+  return true;
+}
+
+bool DBHandleProvider::UpdateCacheAppByPkgid(sqlite3* db, uid_t uid,
+    const std::string& pkgid, const std::string& locale) {
+  auto it = pkg_map_.find(pkgid);
+  if (it == pkg_map_.end()) {
+    LOG(ERROR) << "Can not find package from pkg_map";
+    return false;
+  }
+
+  auto& pkg = it->second;
+  pkgmgrinfo_filter_x tmp_filter = { 0, };
+  pkgmgrinfo_node_x node = {
+    .prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE,
+    .value = pkg->package
+  };
+
+  tmp_filter.cache_flag = true;
+  tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
+
+  std::vector<std::shared_ptr<application_x>> app_list;
+  pkgmgr_server::internal::appinfo_internal_filter_get_list(
+      db, &tmp_filter, uid_, uid, locale.c_str(), app_list);
+
+  for (auto& appid : pkg_app_map_[pkgid]) {
+    app_map_.erase(appid);
+  }
+  pkg_app_map_.erase(pkgid);
+
+  for (auto& app : app_list) {
+    app->privileges = pkg->privileges;
+    std::string appid = app->appid;
+    AddApplication(std::move(appid), std::move(app));
+  }
+
+  g_slist_free(tmp_filter.list);
+  return true;
+}
+
 }  // namespace database
 }  // namespace pkgmgr_server