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;
81 namespace pkgmgr_server {
84 std::unordered_map<uid_t, std::unique_ptr<DBHandleProvider>>
85 DBHandleProvider::provider_map_;
86 std::string DBHandleProvider::global_parser_filedb_path_;
87 std::string DBHandleProvider::cert_filedb_path_;
88 std::unordered_set<pid_t> DBHandleProvider::writer_pid_list_;
89 std::shared_mutex DBHandleProvider::pid_list_lock_;
91 DBHandleProvider::DBHandleProvider(uid_t uid) : uid_(uid) {
94 if (global_parser_filedb_path_.empty()) {
95 tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
96 global_parser_filedb_path_ = tmp_path;
100 if (cert_filedb_path_.empty()) {
101 tmp_path = getUserPkgCertDBPath();
102 cert_filedb_path_ = tmp_path;
106 tmp_path = getUserPkgParserDBPathUID(uid_);
107 user_parser_filedb_path_ = tmp_path;
111 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
112 static std::shared_mutex singleton_lock_;
113 std::shared_lock<std::shared_mutex> s(singleton_lock_);
115 uid = ConvertUID(uid);
116 auto it = provider_map_.find(uid);
117 if (it != provider_map_.end())
118 return *(it->second);
121 std::unique_lock<std::shared_mutex> u(singleton_lock_);
122 auto& prov = provider_map_[uid];
124 prov.reset(new DBHandleProvider(uid));
129 std::unordered_set<pid_t> DBHandleProvider::CrashedWriteRequestPIDs() {
130 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
132 if (writer_pid_list_.empty())
135 LOG(DEBUG) << "Check process count : " << writer_pid_list_.size();
136 std::unordered_set<pid_t> remove_pids;
137 for (pid_t pid : writer_pid_list_) {
138 std::string status_path = "/proc/" + std::to_string(pid) + "/status";
140 int fd = open(status_path.c_str(), O_RDONLY);
142 LOG(ERROR) << "Process is crashed : " << pid;
143 remove_pids.emplace(pid);
152 std::vector<std::pair<std::string, uid_t>> DBHandleProvider::GetParserDBPath() {
153 std::vector<std::pair<std::string, uid_t>> db_path_list;
155 if (uid_ > REGULAR_USER)
156 db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_));
158 db_path_list.emplace_back(
159 std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
161 if (db_path_list.size() == 1) {
162 LOG(DEBUG) << "global db path : " << db_path_list[0].first;
164 LOG(DEBUG) << "local db path : " << db_path_list[0].first;
165 LOG(DEBUG) << "global db path : " << db_path_list[1].first;
171 std::string DBHandleProvider::GetCertDBPath() {
172 return cert_filedb_path_;
175 void DBHandleProvider::TrimCache() {
180 void DBHandleProvider::ReleaseCache() {
181 auto lock = CacheFlag::GetWriterLock();
182 CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
186 pending_pkg_.clear();
187 pkg_app_map_.clear();
188 CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
193 bool DBHandleProvider::IsWriter(pid_t pid) {
194 std::unique_lock<std::shared_mutex> s(pid_list_lock_);
195 return writer_pid_list_.find(pid) != writer_pid_list_.end();
198 int DBHandleProvider::UpdateCache(const tizen_base::Database& db, pid_t pid,
199 uid_t uid, bool write, const std::string& locale) {
202 pending_pkg_.clear();
203 pkg_app_map_.clear();
205 const char* dbpath = sqlite3_db_filename(db.GetRaw(), "main");
207 timespec start_time = { 0, };
208 timespec end_time = { 0, };
209 if (!GetModifiedTime(dbpath, &start_time))
210 return PMINFO_R_ERROR;
212 pkgmgrinfo_filter_x tmp_filter = { 0, };
213 tmp_filter.cache_flag = true;
214 std::map<std::string, std::shared_ptr<package_x>> pkgs;
215 int ret = internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
216 if (ret == PMINFO_R_OK) {
217 for (auto& [key, val] : pkgs)
218 AddPackage(std::move(val));
221 if (!GetModifiedTime(dbpath, &end_time))
222 return PMINFO_R_ERROR;
224 if (start_time.tv_sec != end_time.tv_sec ||
225 start_time.tv_nsec != end_time.tv_nsec) {
226 LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
227 return PMINFO_R_ERROR;
230 std::vector<std::shared_ptr<application_x>> app_list;
231 ret = internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
233 if (!GetModifiedTime(dbpath, &end_time))
234 return PMINFO_R_ERROR;
236 if (start_time.tv_sec != end_time.tv_sec ||
237 start_time.tv_nsec != end_time.tv_nsec) {
238 LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
239 return PMINFO_R_ERROR;
242 if (ret == PMINFO_R_OK) {
243 for (auto& app : app_list) {
244 auto it = pkg_map_.find(app->package);
245 if (it == pkg_map_.end()) {
246 LOG(ERROR) << "Can not find package from pkg_map";
247 return PMINFO_R_ERROR;
250 app->privileges = it->second->privileges;
251 AddApplication(std::move(app));
260 inline bool CheckMetadataFilter(GList* metadata_list,
261 const std::unordered_map<std::string, std::string>& metadata_map) {
262 for (auto* it = metadata_list; it != nullptr; it = g_list_next(it)) {
263 auto* node = reinterpret_cast<metadata_x*>(it->data);
264 if (node->key != nullptr) {
265 auto metadata = metadata_map.find(node->key);
266 if (metadata == metadata_map.end())
269 if (metadata->second.empty() ||
270 strcmp(node->value ? node->value : "", metadata->second.c_str()) == 0)
277 inline bool CheckPkgFilters(pkgmgrinfo_filter_x* filter,
278 const std::shared_ptr<package_x>& info,
279 const std::unordered_map<std::string, std::string>& metadata_map) {
280 for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
281 auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
282 auto* checker = FilterCheckerProvider::GetInst().
283 GetPkgFilterChecker(node->prop);
284 if (!checker->CheckFilter(node, info.get()))
289 if (!metadata_map.empty())
290 pass = CheckMetadataFilter(info->metadata, metadata_map);
295 std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
296 pid_t pid, pkgmgrinfo_filter_x* filter,
297 const std::string& package) {
298 std::vector<std::shared_ptr<package_x>> ret;
300 /* make metadata filter map */
301 std::unordered_map<std::string, std::string> metadata_map;
302 for (auto* it = filter->list_pkg_metadata; it != nullptr;
303 it = g_slist_next(it)) {
304 auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
305 if (node->key == nullptr)
307 LOG(ERROR) << "add metadata filter";
308 metadata_map[node->key] = (node->value ? node->value : "");
311 if (internal::CheckPackageStorageStatus(filter)) {
312 if (pkgmgrinfo_pkginfo_filter_add_bool(filter,
313 PMINFO_PKGINFO_PROP_PACKAGE_CHECK_STORAGE, true) != PMINFO_R_OK) {
314 LOG(ERROR) << "Fail to add check storage value to filter";
318 if (package.empty()) {
319 for (auto& info : pkg_map_) {
320 if (CheckPkgFilters(filter, info.second, metadata_map))
321 ret.push_back(info.second);
324 auto map_it = pkg_map_.find(package);
325 if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second,
327 ret.push_back(map_it->second);
333 void DBHandleProvider::AddPackage(std::shared_ptr<package_x> info) {
334 pkg_map_[info->package] = std::move(info);
337 void DBHandleProvider::AddApplication(std::shared_ptr<application_x> info) {
338 std::string appid = info->appid;
339 std::string pkgid = info->package;
340 app_map_[appid] = std::move(info);
341 pkg_app_map_[pkgid].emplace(std::move(appid));
344 void DBHandleProvider::ErasePackage(const std::string& pkgid) {
345 auto it = pkg_app_map_.find(pkgid);
346 if (it != pkg_app_map_.end()) {
347 for (const auto& app : it->second)
349 pkg_app_map_.erase(it);
352 pkg_map_.erase(pkgid);
355 inline bool CheckAppFilters(pkgmgrinfo_filter_x* filter,
356 const std::shared_ptr<application_x>& app_info,
357 const std::shared_ptr<package_x>& pkg_info,
358 const std::unordered_map<std::string, std::string>& metadata_map) {
359 for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
360 auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
361 auto* checker = FilterCheckerProvider::GetInst().
362 GetAppFilterChecker(node->prop);
363 if (!checker->CheckFilter(node, app_info.get(), pkg_info.get()))
368 if (!metadata_map.empty())
369 pass = CheckMetadataFilter(app_info->metadata, metadata_map);
373 std::shared_ptr<package_x> DBHandleProvider::GetPackageByApp(
375 auto it = pkg_map_.find(appid);
376 if (it == pkg_map_.end())
382 std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
383 pid_t pid, pkgmgrinfo_filter_x* filter,
384 const std::string& app) {
385 /* make metadata filter map */
386 std::unordered_map<std::string, std::string> metadata_map;
387 for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
388 auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
389 if (node->key == nullptr)
392 metadata_map[node->key] = (node->value ? node->value : "");
395 std::vector<std::shared_ptr<application_x>> ret;
396 if (internal::CheckAppStorageStatus(filter)) {
397 if (pkgmgrinfo_appinfo_filter_add_bool(filter,
398 PMINFO_APPINFO_PROP_APP_CHECK_STORAGE, true) != PMINFO_R_OK) {
399 LOG(ERROR) << "Fail to add check storage value to filter";
405 for (auto& info : app_map_) {
406 if (CheckAppFilters(filter, info.second,
407 GetPackageByApp(info.second->package), metadata_map))
408 ret.push_back(info.second);
411 auto map_it = app_map_.find(app);
412 if (map_it != app_map_.end() &&
413 CheckAppFilters(filter, map_it->second,
414 GetPackageByApp(map_it->second->package), metadata_map))
415 ret.push_back(map_it->second);
421 void DBHandleProvider::InsertWriterPID(pid_t pid) {
422 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
424 writer_pid_list_.insert(pid);
427 bool DBHandleProvider::EraseWriterPID(pid_t pid) {
428 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
430 return writer_pid_list_.erase(pid) == 1;
433 void DBHandleProvider::RegisterPendingPackageInfo(
434 const tizen_base::Database& db, package_x* info, pid_t pid, uid_t uid,
435 const std::string& locale, pkgmgr_common::PkgWriteType write_type) {
436 if (!info || !info->package)
439 InsertWriterPID(pid);
441 if (write_type != pkgmgr_common::PkgWriteType::Delete) {
442 pkgmgrinfo_filter_x tmp_filter = { 0, };
443 pkgmgrinfo_node_x node = {
444 .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID
446 tmp_filter.cache_flag = true;
447 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
448 std::map<std::string, std::shared_ptr<package_x>> pkgs;
450 node.value = const_cast<char*>(info->package);
451 internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
452 node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
453 for (auto& [pkgid, pkg_handle] : pkgs) {
454 node.value = const_cast<char*>(pkgid.c_str());
455 std::vector<std::shared_ptr<application_x>> app_list;
456 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
458 for (auto& app : app_list) {
459 app->privileges = pkg_handle->privileges;
460 pending_app_[pkgid].emplace_back(std::move(app));
463 pending_pkg_[pkgid] = std::make_pair(pid, std::move(pkg_handle));
466 g_slist_free(tmp_filter.list);
468 pending_pkg_[info->package] = std::make_pair(pid, nullptr);
469 pending_app_.erase(info->package);
473 void DBHandleProvider::UpdatePendingPackageInfo(
474 const std::vector<std::string>& pkgids) {
475 for (const auto& pkgid : pkgids) {
476 auto pkg_it = pending_pkg_.find(pkgid);
477 if (pkg_it == pending_pkg_.end())
481 auto app_it = pending_app_.find(pkgid);
482 if (app_it != pending_app_.end()) {
483 for (auto& app : app_it->second)
484 AddApplication(std::move(app));
485 pending_app_.erase(app_it);
488 if (pkg_it->second.second)
489 AddPackage(std::move(pkg_it->second.second));
491 EraseWriterPID(pkg_it->second.first);
492 pending_pkg_.erase(pkg_it);
496 void DBHandleProvider::UpdateCrashedWriterPackageInfo(
497 const std::unordered_set<pid_t>& pids) {
498 for (auto it = pending_pkg_.begin(); it != pending_pkg_.end();) {
499 pid_t pid = it->second.first;
500 if (pids.find(pid) == pids.end()) {
505 const auto& pkgid = it->first;
506 auto old_app_it = pkg_app_map_.find(pkgid);
507 if (old_app_it != pkg_app_map_.end()) {
508 for (const auto& app : old_app_it->second)
511 pkg_app_map_.erase(old_app_it);
514 auto app_it = pending_app_.find(pkgid);
515 if (app_it != pending_app_.end()) {
516 for (auto& app : app_it->second)
517 AddApplication(std::move(app));
518 pending_app_.erase(app_it);
521 if (it->second.second)
522 AddPackage(std::move(it->second.second));
524 EraseWriterPID(it->second.first);
525 it = pending_pkg_.erase(it);
529 bool DBHandleProvider::UpdateCachePkg(const tizen_base::Database& db, uid_t uid,
530 const std::string& pkgid, const std::string& locale) {
531 pkgmgrinfo_filter_x tmp_filter = { 0, };
532 pkgmgrinfo_node_x node = {
533 .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID,
534 .value = const_cast<char*>(pkgid.c_str())
536 tmp_filter.cache_flag = true;
537 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
538 std::map<std::string, std::shared_ptr<package_x>> pkgs;
539 internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
540 for (auto& [key, val] : pkgs) {
542 for (auto& appid : pkg_app_map_[key])
543 app_map_.erase(appid);
545 pkg_app_map_.erase(key);
546 std::vector<std::shared_ptr<application_x>> app_list;
547 node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
548 node.value = const_cast<char*>(key.c_str());
549 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
550 for (auto& app : app_list) {
551 app->privileges = val->privileges;
552 AddApplication(std::move(app));
559 bool DBHandleProvider::UpdateCacheApp(const tizen_base::Database& db, uid_t uid,
560 const std::string& appid, const std::string& locale) {
561 pkgmgrinfo_filter_x tmp_filter = { 0, };
562 pkgmgrinfo_node_x node = {
563 .prop = E_PMINFO_APPINFO_PROP_APP_ID,
564 .value = const_cast<char*>(appid.c_str())
566 tmp_filter.cache_flag = true;
567 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
569 std::vector<std::shared_ptr<application_x>> app_list;
570 app_map_.erase(appid);
571 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
572 g_slist_free(tmp_filter.list);
574 for (auto& app : app_list) {
575 auto it = pkg_map_.find(app->package);
576 if (it == pkg_map_.end()) {
577 LOG(ERROR) << "Can not find package from pkg_map";
581 pkg_app_map_[app->package].erase(app->appid);
582 app->privileges = it->second->privileges;
583 AddApplication(std::move(app));
589 bool DBHandleProvider::UpdateCacheAppByPkgid(const tizen_base::Database& db,
590 uid_t uid, const std::string& pkgid, const std::string& locale) {
591 auto it = pkg_map_.find(pkgid);
592 if (it == pkg_map_.end()) {
593 LOG(ERROR) << "Can not find package from pkg_map";
597 auto& pkg = it->second;
598 pkgmgrinfo_filter_x tmp_filter = { 0, };
599 pkgmgrinfo_node_x node = {
600 .prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE,
601 .value = pkg->package
604 tmp_filter.cache_flag = true;
605 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
607 std::vector<std::shared_ptr<application_x>> app_list;
608 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
610 for (auto& appid : pkg_app_map_[pkgid]) {
611 app_map_.erase(appid);
613 pkg_app_map_.erase(pkgid);
615 for (auto& app : app_list) {
616 app->privileges = pkg->privileges;
617 AddApplication(std::move(app));
620 g_slist_free(tmp_filter.list);
624 } // namespace database
625 } // namespace pkgmgr_server