2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "db_handle_provider.hh"
22 #include <sys/types.h>
24 #include <tzplatform_config.h>
30 #include "cache_flag.hh"
31 #include "utils/logging.hh"
33 #include "pkgmgr-info.h"
34 #include "pkgmgrinfo_debug.h"
35 #include "pkgmgrinfo_internal.h"
36 #include "pkgmgrinfo_private.h"
41 #define LOG_TAG "PKGMGR_INFO"
45 uid_t globaluser_uid = -1;
47 uid_t GetGlobalUID() {
48 if (globaluser_uid == (uid_t)-1)
49 globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
51 return globaluser_uid;
54 uid_t ConvertUID(uid_t uid) {
55 if (uid < REGULAR_USER)
56 return GetGlobalUID();
61 bool GetModifiedTime(const char* dbpath, timespec* t) {
62 if (dbpath == nullptr || t == nullptr) {
63 LOG(ERROR) << "Invalid argument";
68 if (stat(dbpath, &attr)) {
69 LOG(ERROR) << "Fail to get status from file "
70 << dbpath << " errno : " << errno;
79 static const std::string global_parser_memdb_path =
80 "file:parserdb?mode=memory&cache=shared";
82 static const std::string cert_memdb_path =
83 "file:certdb?mode=memory&cache=shared";
87 namespace pkgmgr_server {
90 std::unordered_map<uid_t, std::unique_ptr<DBHandleProvider>>
91 DBHandleProvider::provider_map_;
92 bool DBHandleProvider::is_global_memdb_set_ = false;
93 std::unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
94 DBHandleProvider::global_parser_memdb_handle_(nullptr,
96 std::unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
97 DBHandleProvider::cert_memdb_handle_(nullptr, sqlite3_close_v2);
98 std::string DBHandleProvider::global_parser_filedb_path_;
99 std::string DBHandleProvider::cert_filedb_path_;
100 std::unordered_set<pid_t> DBHandleProvider::writer_pid_list_;
101 std::recursive_mutex DBHandleProvider::lock_;
102 std::shared_mutex DBHandleProvider::pid_list_lock_;
104 DBHandleProvider::DBHandleProvider(uid_t uid)
106 is_user_memdb_set_(false),
107 parser_memdb_handle_(nullptr, sqlite3_close_v2) {
110 if (global_parser_filedb_path_.empty()) {
111 tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
112 global_parser_filedb_path_ = tmp_path;
116 if (cert_filedb_path_.empty()) {
117 tmp_path = getUserPkgCertDBPath();
118 cert_filedb_path_ = tmp_path;
122 tmp_path = getUserPkgParserDBPathUID(uid_);
123 user_parser_filedb_path_ = tmp_path;
126 user_parser_memdb_path_ = "file:parserdb" +
127 std::to_string(static_cast<int>(uid_)) +
128 "?mode=memory&cache=shared";
131 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
132 static std::shared_mutex singleton_lock_;
133 std::shared_lock<std::shared_mutex> s(singleton_lock_);
135 uid = ConvertUID(uid);
136 auto it = provider_map_.find(uid);
137 if (it != provider_map_.end())
138 return *(it->second);
141 std::unique_lock<std::shared_mutex> u(singleton_lock_);
142 auto& prov = provider_map_[uid];
144 prov.reset(new DBHandleProvider(uid));
149 bool DBHandleProvider::IsCrashedWriteRequest() {
150 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
152 if (writer_pid_list_.empty())
156 LOG(DEBUG) << "Check process count : " << writer_pid_list_.size();
157 std::vector<pid_t> remove_pids;
158 for (pid_t pid : writer_pid_list_) {
159 std::string status_path = "/proc/" + std::to_string(pid) + "/status";
161 int fd = open(status_path.c_str(), O_RDONLY);
163 LOG(ERROR) << "Process is crashed : " << pid;
164 remove_pids.push_back(pid);
171 for (pid_t pid : remove_pids)
172 writer_pid_list_.erase(pid);
177 std::vector<std::pair<std::string, uid_t>> DBHandleProvider::GetParserDBPath(
178 pid_t pid, bool write) {
179 std::unique_lock<std::recursive_mutex> u(lock_);
180 std::vector<std::pair<std::string, uid_t>> db_path_list;
182 if (is_user_memdb_set_ != is_global_memdb_set_)
183 is_global_memdb_set_ ? SetMemoryMode(pid) : UnsetMemoryMode(pid);
185 if (IsMemoryDBActive(pid, write)) {
186 if (uid_ > REGULAR_USER)
187 db_path_list.emplace_back(std::make_pair(user_parser_memdb_path_, uid_));
189 db_path_list.emplace_back(
190 std::make_pair(global_parser_memdb_path, GetGlobalUID()));
192 if (uid_ > REGULAR_USER)
193 db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_));
195 db_path_list.emplace_back(
196 std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
199 if (db_path_list.size() == 1) {
200 LOG(DEBUG) << "global db path : " << db_path_list[0].first;
202 LOG(DEBUG) << "local db path : " << db_path_list[0].first;
203 LOG(DEBUG) << "global db path : " << db_path_list[1].first;
209 std::string DBHandleProvider::GetCertDBPath(pid_t pid, bool write) {
210 std::unique_lock<std::recursive_mutex> u(lock_);
211 if (is_user_memdb_set_ != is_global_memdb_set_)
212 is_global_memdb_set_ ? SetMemoryMode(pid) : UnsetMemoryMode(pid);
214 if (IsMemoryDBActive(pid, write))
215 return cert_memdb_path;
217 return cert_filedb_path_;
220 sqlite3* DBHandleProvider::CreateMemoryDBHandle(const std::string& filedb_path,
221 const std::string& memorydb_path) {
222 sqlite3* memorydb = nullptr;
223 sqlite3* filedb = nullptr;
224 LOG(INFO) << "Create memory db handle : " << memorydb_path;
225 int ret = sqlite3_open_v2(memorydb_path.c_str(), &memorydb,
226 SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, nullptr);
227 if (ret != SQLITE_OK) {
228 LOG(ERROR) << "Failed to open memory DB " << ret << ": " << memorydb_path;
232 ret = sqlite3_open_v2(filedb_path.c_str(), &filedb, SQLITE_OPEN_READONLY,
234 if (ret != SQLITE_OK) {
235 LOG(ERROR) << "Failed to open file DB " << ret << ": " << filedb_path;
236 sqlite3_close_v2(memorydb);
240 sqlite3_backup* backup =
241 sqlite3_backup_init(memorydb, "main", filedb, "main");
242 if (backup == nullptr) {
243 LOG(ERROR) << "Failed to backup for memory DB";
244 sqlite3_close_v2(memorydb);
245 sqlite3_close_v2(filedb);
249 sqlite3_backup_step(backup, -1);
250 sqlite3_backup_finish(backup);
251 sqlite3_close_v2(filedb);
252 LOG(INFO) << "Create memory db handle done";
256 void DBHandleProvider::SetMemoryMode(pid_t pid) {
257 std::unique_lock<std::recursive_mutex> u(lock_);
258 if (is_global_memdb_set_ && is_user_memdb_set_)
262 CreateMemoryDBHandle(user_parser_filedb_path_, user_parser_memdb_path_);
263 if (parser_db != nullptr)
264 parser_memdb_handle_.reset(parser_db);
266 if (is_user_memdb_set_ == is_global_memdb_set_) {
267 sqlite3* global_parser_file_db = CreateMemoryDBHandle(
268 global_parser_filedb_path_, global_parser_memdb_path);
269 if (global_parser_file_db)
270 global_parser_memdb_handle_.reset(global_parser_file_db);
273 CreateMemoryDBHandle(cert_filedb_path_, cert_memdb_path);
274 if (cert_db != nullptr)
275 cert_memdb_handle_.reset(cert_db);
280 is_user_memdb_set_ = true;
281 is_global_memdb_set_ = true;
282 LOG(INFO) << "Set Memory mode : Memory";
285 void DBHandleProvider::UnsetMemoryMode(pid_t pid) {
286 std::unique_lock<std::recursive_mutex> u(lock_);
287 if (!is_global_memdb_set_ && !is_user_memdb_set_)
290 parser_memdb_handle_.reset(nullptr);
291 cert_memdb_handle_.reset(nullptr);
292 global_parser_memdb_handle_.reset(nullptr);
295 LOG(ERROR) << "Given pid is not exists in pid list : " << pid;
297 is_user_memdb_set_ = false;
298 is_global_memdb_set_ = false;
300 LOG(DEBUG) << "Set Memory mode : File";
303 bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) {
304 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
305 if (!is_user_memdb_set_)
311 if (writer_pid_list_.find(pid) != writer_pid_list_.end())
317 void DBHandleProvider::TrimCache() {
318 std::unique_lock<std::recursive_mutex> u(lock_);
323 void DBHandleProvider::ReleaseCache() {
324 auto lock = CacheFlag::GetWriterLock();
325 CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
329 pending_pkg_.clear();
330 pkg_app_map_.clear();
331 CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
336 bool DBHandleProvider::IsWriter(pid_t pid) {
337 std::unique_lock<std::shared_mutex> s(pid_list_lock_);
338 return writer_pid_list_.find(pid) != writer_pid_list_.end();
341 int DBHandleProvider::UpdateCache(const tizen_base::Database& db, pid_t pid,
342 uid_t uid, bool write, const std::string& locale) {
345 pending_pkg_.clear();
346 pkg_app_map_.clear();
348 const char* dbpath = sqlite3_db_filename(db.GetRaw(), "main");
349 bool is_inmemory_db = false;
350 if (dbpath == nullptr || strlen(dbpath) == 0) {
351 LOG(INFO) << "database is inmemory db";
352 is_inmemory_db = true;
355 timespec start_time = { 0, };
356 timespec end_time = { 0, };
357 if (!is_inmemory_db && !GetModifiedTime(dbpath, &start_time))
358 return PMINFO_R_ERROR;
360 pkgmgrinfo_filter_x tmp_filter = { 0, };
361 tmp_filter.cache_flag = true;
362 std::map<std::string, std::shared_ptr<package_x>> pkgs;
363 int ret = internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
364 if (ret == PMINFO_R_OK) {
365 for (auto& [key, val] : pkgs)
366 AddPackage(std::move(key), std::move(val));
369 if (!is_inmemory_db && !GetModifiedTime(dbpath, &end_time))
370 return PMINFO_R_ERROR;
372 if (start_time.tv_sec != end_time.tv_sec ||
373 start_time.tv_nsec != end_time.tv_nsec) {
374 LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
375 return PMINFO_R_ERROR;
378 std::vector<std::shared_ptr<application_x>> app_list;
379 ret = internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
381 if (!is_inmemory_db && !GetModifiedTime(dbpath, &end_time))
382 return PMINFO_R_ERROR;
384 if (start_time.tv_sec != end_time.tv_sec ||
385 start_time.tv_nsec != end_time.tv_nsec) {
386 LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
387 return PMINFO_R_ERROR;
390 if (ret == PMINFO_R_OK) {
391 for (auto& app : app_list) {
392 auto it = pkg_map_.find(app->package);
393 if (it == pkg_map_.end()) {
394 LOG(ERROR) << "Can not find package from pkg_map";
395 return PMINFO_R_ERROR;
398 app->privileges = it->second->privileges;
399 std::string appid = app->appid;
400 AddApplication(std::move(appid), std::move(app));
409 inline bool CheckMetadataFilter(GList* metadata_list,
410 const std::unordered_map<std::string, std::string>& metadata_map) {
411 for (auto* it = metadata_list; it != nullptr; it = g_list_next(it)) {
412 auto* node = reinterpret_cast<metadata_x*>(it->data);
413 if (node->key != nullptr) {
414 auto metadata = metadata_map.find(node->key);
415 if (metadata == metadata_map.end())
418 if (metadata->second.empty() ||
419 strcmp(node->value ? node->value : "", metadata->second.c_str()) == 0)
426 inline bool CheckPkgFilters(pkgmgrinfo_filter_x* filter,
427 const std::shared_ptr<package_x>& info,
428 const std::unordered_map<std::string, std::string>& metadata_map) {
429 for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
430 auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
431 auto* checker = FilterCheckerProvider::GetInst().
432 GetPkgFilterChecker(node->prop);
433 if (!checker->CheckFilter(node, info.get()))
438 if (!metadata_map.empty())
439 pass = CheckMetadataFilter(info->metadata, metadata_map);
444 std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
445 pid_t pid, pkgmgrinfo_filter_x* filter,
446 const std::string& package) {
447 std::vector<std::shared_ptr<package_x>> ret;
449 /* make metadata filter map */
450 std::unordered_map<std::string, std::string> metadata_map;
451 for (auto* it = filter->list_pkg_metadata; it != nullptr;
452 it = g_slist_next(it)) {
453 auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
454 if (node->key == nullptr)
456 LOG(ERROR) << "add metadata filter";
457 metadata_map[node->key] = (node->value ? node->value : "");
460 if (internal::CheckPackageStorageStatus(filter)) {
461 if (pkgmgrinfo_pkginfo_filter_add_bool(filter,
462 PMINFO_PKGINFO_PROP_PACKAGE_CHECK_STORAGE, true) != PMINFO_R_OK) {
463 LOG(ERROR) << "Fail to add check storage value to filter";
467 if (package.empty()) {
468 for (auto& info : pkg_map_) {
469 if (CheckPkgFilters(filter, info.second, metadata_map))
470 ret.push_back(info.second);
473 auto map_it = pkg_map_.find(package);
474 if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second,
476 ret.push_back(map_it->second);
482 void DBHandleProvider::AddPackage(std::string package,
483 std::shared_ptr<package_x> info) {
484 pkg_map_[package] = std::move(info);
487 inline bool CheckAppFilters(pkgmgrinfo_filter_x* filter,
488 const std::shared_ptr<application_x>& app_info,
489 const std::shared_ptr<package_x>& pkg_info,
490 const std::unordered_map<std::string, std::string>& metadata_map) {
491 for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
492 auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
493 auto* checker = FilterCheckerProvider::GetInst().
494 GetAppFilterChecker(node->prop);
495 if (!checker->CheckFilter(node, app_info.get(), pkg_info.get()))
500 if (!metadata_map.empty())
501 pass = CheckMetadataFilter(app_info->metadata, metadata_map);
505 std::shared_ptr<package_x> DBHandleProvider::GetPackageByApp(
507 auto it = pkg_map_.find(appid);
508 if (it == pkg_map_.end())
514 std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
515 pid_t pid, pkgmgrinfo_filter_x* filter,
516 const std::string& app) {
517 /* make metadata filter map */
518 std::unordered_map<std::string, std::string> metadata_map;
519 for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
520 auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
521 if (node->key == nullptr)
524 metadata_map[node->key] = (node->value ? node->value : "");
527 std::vector<std::shared_ptr<application_x>> ret;
528 if (internal::CheckAppStorageStatus(filter)) {
529 if (pkgmgrinfo_appinfo_filter_add_bool(filter,
530 PMINFO_APPINFO_PROP_APP_CHECK_STORAGE, true) != PMINFO_R_OK) {
531 LOG(ERROR) << "Fail to add check storage value to filter";
537 for (auto& info : app_map_) {
538 if (CheckAppFilters(filter, info.second,
539 GetPackageByApp(info.second->package), metadata_map))
540 ret.push_back(info.second);
543 auto map_it = app_map_.find(app);
544 if (map_it != app_map_.end() &&
545 CheckAppFilters(filter, map_it->second,
546 GetPackageByApp(map_it->second->package), metadata_map))
547 ret.push_back(map_it->second);
553 void DBHandleProvider::AddApplication(std::string app,
554 std::shared_ptr<application_x> info) {
555 pkg_app_map_[info->package].emplace(app);
556 app_map_[app] = std::move(info);
559 void DBHandleProvider::InsertPID(pid_t pid) {
560 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
562 writer_pid_list_.insert(pid);
565 bool DBHandleProvider::ErasePID(pid_t pid) {
566 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
568 return writer_pid_list_.erase(pid) == 1;
571 void DBHandleProvider::RegisterPendingPackageInfo(package_x* info) {
572 if (!info || !info->package)
575 pending_pkg_.emplace(info->package);
578 void DBHandleProvider::UpdatePendingPackageInfo(const tizen_base::Database& db,
579 pid_t pid, uid_t uid, const std::string& locale) {
580 pkgmgrinfo_filter_x tmp_filter = { 0, };
581 pkgmgrinfo_node_x node = {
582 .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID
584 tmp_filter.cache_flag = true;
585 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
586 std::map<std::string, std::shared_ptr<package_x>> pkgs;
587 for (const auto& pkg : pending_pkg_) {
589 for (auto& appid : pkg_app_map_[pkg]) {
590 app_map_.erase(appid);
593 pkg_app_map_.erase(pkg);
594 node.value = const_cast<char*>(pkg.c_str());
595 internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
598 for (auto& [key, val] : pkgs)
599 AddPackage(key, val);
601 node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
602 for (auto& [key, val] : pkgs) {
603 node.value = val->package;
604 std::vector<std::shared_ptr<application_x>> app_list;
605 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
607 for (auto& app : app_list) {
608 app->privileges = val->privileges;
609 std::string appid = app->appid;
610 AddApplication(std::move(appid), std::move(app));
614 g_slist_free(tmp_filter.list);
615 pending_pkg_.clear();
618 bool DBHandleProvider::UpdateCachePkg(const tizen_base::Database& db, uid_t uid,
619 const std::string& pkgid, const std::string& locale) {
620 pkgmgrinfo_filter_x tmp_filter = { 0, };
621 pkgmgrinfo_node_x node = {
622 .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID,
623 .value = const_cast<char*>(pkgid.c_str())
625 tmp_filter.cache_flag = true;
626 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
627 std::map<std::string, std::shared_ptr<package_x>> pkgs;
628 internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
629 for (auto& [key, val] : pkgs) {
630 AddPackage(key, val);
631 for (auto& appid : pkg_app_map_[key]) {
632 app_map_.erase(appid);
635 pkg_app_map_.erase(key);
636 std::vector<std::shared_ptr<application_x>> app_list;
637 node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
638 node.value = const_cast<char*>(key.c_str());
639 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
640 for (auto& app : app_list) {
641 app->privileges = val->privileges;
642 std::string appid = app->appid;
643 AddApplication(std::move(appid), std::move(app));
650 bool DBHandleProvider::UpdateCacheApp(const tizen_base::Database& db, uid_t uid,
651 const std::string& appid, const std::string& locale) {
652 pkgmgrinfo_filter_x tmp_filter = { 0, };
653 pkgmgrinfo_node_x node = {
654 .prop = E_PMINFO_APPINFO_PROP_APP_ID,
655 .value = const_cast<char*>(appid.c_str())
657 tmp_filter.cache_flag = true;
658 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
660 std::vector<std::shared_ptr<application_x>> app_list;
661 app_map_.erase(appid);
662 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
663 g_slist_free(tmp_filter.list);
665 for (auto& app : app_list) {
666 auto it = pkg_map_.find(app->package);
667 if (it == pkg_map_.end()) {
668 LOG(ERROR) << "Can not find package from pkg_map";
672 pkg_app_map_[app->package].erase(app->appid);
673 app->privileges = it->second->privileges;
674 std::string appid = app->appid;
675 AddApplication(std::move(appid), std::move(app));
681 bool DBHandleProvider::UpdateCacheAppByPkgid(const tizen_base::Database& db,
682 uid_t uid, const std::string& pkgid, const std::string& locale) {
683 auto it = pkg_map_.find(pkgid);
684 if (it == pkg_map_.end()) {
685 LOG(ERROR) << "Can not find package from pkg_map";
689 auto& pkg = it->second;
690 pkgmgrinfo_filter_x tmp_filter = { 0, };
691 pkgmgrinfo_node_x node = {
692 .prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE,
693 .value = pkg->package
696 tmp_filter.cache_flag = true;
697 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
699 std::vector<std::shared_ptr<application_x>> app_list;
700 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
702 for (auto& appid : pkg_app_map_[pkgid]) {
703 app_map_.erase(appid);
705 pkg_app_map_.erase(pkgid);
707 for (auto& app : app_list) {
708 app->privileges = pkg->privileges;
709 std::string appid = app->appid;
710 AddApplication(std::move(appid), std::move(app));
713 g_slist_free(tmp_filter.list);
717 } // namespace database
718 } // namespace pkgmgr_server