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::recursive_mutex DBHandleProvider::lock_;
90 std::shared_mutex DBHandleProvider::pid_list_lock_;
92 DBHandleProvider::DBHandleProvider(uid_t uid) : uid_(uid) {
95 if (global_parser_filedb_path_.empty()) {
96 tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
97 global_parser_filedb_path_ = tmp_path;
101 if (cert_filedb_path_.empty()) {
102 tmp_path = getUserPkgCertDBPath();
103 cert_filedb_path_ = tmp_path;
107 tmp_path = getUserPkgParserDBPathUID(uid_);
108 user_parser_filedb_path_ = tmp_path;
112 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
113 static std::shared_mutex singleton_lock_;
114 std::shared_lock<std::shared_mutex> s(singleton_lock_);
116 uid = ConvertUID(uid);
117 auto it = provider_map_.find(uid);
118 if (it != provider_map_.end())
119 return *(it->second);
122 std::unique_lock<std::shared_mutex> u(singleton_lock_);
123 auto& prov = provider_map_[uid];
125 prov.reset(new DBHandleProvider(uid));
130 bool DBHandleProvider::IsCrashedWriteRequest() {
131 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
133 if (writer_pid_list_.empty())
137 LOG(DEBUG) << "Check process count : " << writer_pid_list_.size();
138 std::vector<pid_t> remove_pids;
139 for (pid_t pid : writer_pid_list_) {
140 std::string status_path = "/proc/" + std::to_string(pid) + "/status";
142 int fd = open(status_path.c_str(), O_RDONLY);
144 LOG(ERROR) << "Process is crashed : " << pid;
145 remove_pids.push_back(pid);
152 for (pid_t pid : remove_pids)
153 writer_pid_list_.erase(pid);
158 std::vector<std::pair<std::string, uid_t>> DBHandleProvider::GetParserDBPath() {
159 std::unique_lock<std::recursive_mutex> u(lock_);
160 std::vector<std::pair<std::string, uid_t>> db_path_list;
162 if (uid_ > REGULAR_USER)
163 db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_));
165 db_path_list.emplace_back(
166 std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
168 if (db_path_list.size() == 1) {
169 LOG(DEBUG) << "global db path : " << db_path_list[0].first;
171 LOG(DEBUG) << "local db path : " << db_path_list[0].first;
172 LOG(DEBUG) << "global db path : " << db_path_list[1].first;
178 std::string DBHandleProvider::GetCertDBPath() {
179 return cert_filedb_path_;
182 void DBHandleProvider::TrimCache() {
183 std::unique_lock<std::recursive_mutex> u(lock_);
188 void DBHandleProvider::ReleaseCache() {
189 auto lock = CacheFlag::GetWriterLock();
190 CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
194 pending_pkg_.clear();
195 pkg_app_map_.clear();
196 CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
201 bool DBHandleProvider::IsWriter(pid_t pid) {
202 std::unique_lock<std::shared_mutex> s(pid_list_lock_);
203 return writer_pid_list_.find(pid) != writer_pid_list_.end();
206 int DBHandleProvider::UpdateCache(const tizen_base::Database& db, pid_t pid,
207 uid_t uid, bool write, const std::string& locale) {
210 pending_pkg_.clear();
211 pkg_app_map_.clear();
213 const char* dbpath = sqlite3_db_filename(db.GetRaw(), "main");
215 timespec start_time = { 0, };
216 timespec end_time = { 0, };
217 if (!GetModifiedTime(dbpath, &start_time))
218 return PMINFO_R_ERROR;
220 pkgmgrinfo_filter_x tmp_filter = { 0, };
221 tmp_filter.cache_flag = true;
222 std::map<std::string, std::shared_ptr<package_x>> pkgs;
223 int ret = internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
224 if (ret == PMINFO_R_OK) {
225 for (auto& [key, val] : pkgs)
226 AddPackage(std::move(key), std::move(val));
229 if (!GetModifiedTime(dbpath, &end_time))
230 return PMINFO_R_ERROR;
232 if (start_time.tv_sec != end_time.tv_sec ||
233 start_time.tv_nsec != end_time.tv_nsec) {
234 LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
235 return PMINFO_R_ERROR;
238 std::vector<std::shared_ptr<application_x>> app_list;
239 ret = internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
241 if (!GetModifiedTime(dbpath, &end_time))
242 return PMINFO_R_ERROR;
244 if (start_time.tv_sec != end_time.tv_sec ||
245 start_time.tv_nsec != end_time.tv_nsec) {
246 LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
247 return PMINFO_R_ERROR;
250 if (ret == PMINFO_R_OK) {
251 for (auto& app : app_list) {
252 auto it = pkg_map_.find(app->package);
253 if (it == pkg_map_.end()) {
254 LOG(ERROR) << "Can not find package from pkg_map";
255 return PMINFO_R_ERROR;
258 app->privileges = it->second->privileges;
259 std::string appid = app->appid;
260 AddApplication(std::move(appid), std::move(app));
269 inline bool CheckMetadataFilter(GList* metadata_list,
270 const std::unordered_map<std::string, std::string>& metadata_map) {
271 for (auto* it = metadata_list; it != nullptr; it = g_list_next(it)) {
272 auto* node = reinterpret_cast<metadata_x*>(it->data);
273 if (node->key != nullptr) {
274 auto metadata = metadata_map.find(node->key);
275 if (metadata == metadata_map.end())
278 if (metadata->second.empty() ||
279 strcmp(node->value ? node->value : "", metadata->second.c_str()) == 0)
286 inline bool CheckPkgFilters(pkgmgrinfo_filter_x* filter,
287 const std::shared_ptr<package_x>& info,
288 const std::unordered_map<std::string, std::string>& metadata_map) {
289 for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
290 auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
291 auto* checker = FilterCheckerProvider::GetInst().
292 GetPkgFilterChecker(node->prop);
293 if (!checker->CheckFilter(node, info.get()))
298 if (!metadata_map.empty())
299 pass = CheckMetadataFilter(info->metadata, metadata_map);
304 std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
305 pid_t pid, pkgmgrinfo_filter_x* filter,
306 const std::string& package) {
307 std::vector<std::shared_ptr<package_x>> ret;
309 /* make metadata filter map */
310 std::unordered_map<std::string, std::string> metadata_map;
311 for (auto* it = filter->list_pkg_metadata; it != nullptr;
312 it = g_slist_next(it)) {
313 auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
314 if (node->key == nullptr)
316 LOG(ERROR) << "add metadata filter";
317 metadata_map[node->key] = (node->value ? node->value : "");
320 if (internal::CheckPackageStorageStatus(filter)) {
321 if (pkgmgrinfo_pkginfo_filter_add_bool(filter,
322 PMINFO_PKGINFO_PROP_PACKAGE_CHECK_STORAGE, true) != PMINFO_R_OK) {
323 LOG(ERROR) << "Fail to add check storage value to filter";
327 if (package.empty()) {
328 for (auto& info : pkg_map_) {
329 if (CheckPkgFilters(filter, info.second, metadata_map))
330 ret.push_back(info.second);
333 auto map_it = pkg_map_.find(package);
334 if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second,
336 ret.push_back(map_it->second);
342 void DBHandleProvider::AddPackage(std::string package,
343 std::shared_ptr<package_x> info) {
344 pkg_map_[package] = std::move(info);
347 inline bool CheckAppFilters(pkgmgrinfo_filter_x* filter,
348 const std::shared_ptr<application_x>& app_info,
349 const std::shared_ptr<package_x>& pkg_info,
350 const std::unordered_map<std::string, std::string>& metadata_map) {
351 for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
352 auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
353 auto* checker = FilterCheckerProvider::GetInst().
354 GetAppFilterChecker(node->prop);
355 if (!checker->CheckFilter(node, app_info.get(), pkg_info.get()))
360 if (!metadata_map.empty())
361 pass = CheckMetadataFilter(app_info->metadata, metadata_map);
365 std::shared_ptr<package_x> DBHandleProvider::GetPackageByApp(
367 auto it = pkg_map_.find(appid);
368 if (it == pkg_map_.end())
374 std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
375 pid_t pid, pkgmgrinfo_filter_x* filter,
376 const std::string& app) {
377 /* make metadata filter map */
378 std::unordered_map<std::string, std::string> metadata_map;
379 for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
380 auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
381 if (node->key == nullptr)
384 metadata_map[node->key] = (node->value ? node->value : "");
387 std::vector<std::shared_ptr<application_x>> ret;
388 if (internal::CheckAppStorageStatus(filter)) {
389 if (pkgmgrinfo_appinfo_filter_add_bool(filter,
390 PMINFO_APPINFO_PROP_APP_CHECK_STORAGE, true) != PMINFO_R_OK) {
391 LOG(ERROR) << "Fail to add check storage value to filter";
397 for (auto& info : app_map_) {
398 if (CheckAppFilters(filter, info.second,
399 GetPackageByApp(info.second->package), metadata_map))
400 ret.push_back(info.second);
403 auto map_it = app_map_.find(app);
404 if (map_it != app_map_.end() &&
405 CheckAppFilters(filter, map_it->second,
406 GetPackageByApp(map_it->second->package), metadata_map))
407 ret.push_back(map_it->second);
413 void DBHandleProvider::AddApplication(std::string app,
414 std::shared_ptr<application_x> info) {
415 pkg_app_map_[info->package].emplace(app);
416 app_map_[app] = std::move(info);
419 void DBHandleProvider::InsertPID(pid_t pid) {
420 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
422 writer_pid_list_.insert(pid);
425 bool DBHandleProvider::ErasePID(pid_t pid) {
426 std::unique_lock<std::shared_mutex> u(pid_list_lock_);
428 return writer_pid_list_.erase(pid) == 1;
431 void DBHandleProvider::RegisterPendingPackageInfo(package_x* info) {
432 if (!info || !info->package)
435 pending_pkg_.emplace(info->package);
438 void DBHandleProvider::UpdatePendingPackageInfo(const tizen_base::Database& db,
439 pid_t pid, uid_t uid, const std::string& locale) {
440 pkgmgrinfo_filter_x tmp_filter = { 0, };
441 pkgmgrinfo_node_x node = {
442 .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID
444 tmp_filter.cache_flag = true;
445 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
446 std::map<std::string, std::shared_ptr<package_x>> pkgs;
447 for (const auto& pkg : pending_pkg_) {
449 for (auto& appid : pkg_app_map_[pkg]) {
450 app_map_.erase(appid);
453 pkg_app_map_.erase(pkg);
454 node.value = const_cast<char*>(pkg.c_str());
455 internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
458 for (auto& [key, val] : pkgs)
459 AddPackage(key, val);
461 node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
462 for (auto& [key, val] : pkgs) {
463 node.value = val->package;
464 std::vector<std::shared_ptr<application_x>> app_list;
465 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
467 for (auto& app : app_list) {
468 app->privileges = val->privileges;
469 std::string appid = app->appid;
470 AddApplication(std::move(appid), std::move(app));
474 g_slist_free(tmp_filter.list);
475 pending_pkg_.clear();
478 bool DBHandleProvider::UpdateCachePkg(const tizen_base::Database& db, uid_t uid,
479 const std::string& pkgid, const std::string& locale) {
480 pkgmgrinfo_filter_x tmp_filter = { 0, };
481 pkgmgrinfo_node_x node = {
482 .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID,
483 .value = const_cast<char*>(pkgid.c_str())
485 tmp_filter.cache_flag = true;
486 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
487 std::map<std::string, std::shared_ptr<package_x>> pkgs;
488 internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
489 for (auto& [key, val] : pkgs) {
490 AddPackage(key, val);
491 for (auto& appid : pkg_app_map_[key]) {
492 app_map_.erase(appid);
495 pkg_app_map_.erase(key);
496 std::vector<std::shared_ptr<application_x>> app_list;
497 node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
498 node.value = const_cast<char*>(key.c_str());
499 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
500 for (auto& app : app_list) {
501 app->privileges = val->privileges;
502 std::string appid = app->appid;
503 AddApplication(std::move(appid), std::move(app));
510 bool DBHandleProvider::UpdateCacheApp(const tizen_base::Database& db, uid_t uid,
511 const std::string& appid, const std::string& locale) {
512 pkgmgrinfo_filter_x tmp_filter = { 0, };
513 pkgmgrinfo_node_x node = {
514 .prop = E_PMINFO_APPINFO_PROP_APP_ID,
515 .value = const_cast<char*>(appid.c_str())
517 tmp_filter.cache_flag = true;
518 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
520 std::vector<std::shared_ptr<application_x>> app_list;
521 app_map_.erase(appid);
522 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
523 g_slist_free(tmp_filter.list);
525 for (auto& app : app_list) {
526 auto it = pkg_map_.find(app->package);
527 if (it == pkg_map_.end()) {
528 LOG(ERROR) << "Can not find package from pkg_map";
532 pkg_app_map_[app->package].erase(app->appid);
533 app->privileges = it->second->privileges;
534 std::string appid = app->appid;
535 AddApplication(std::move(appid), std::move(app));
541 bool DBHandleProvider::UpdateCacheAppByPkgid(const tizen_base::Database& db,
542 uid_t uid, const std::string& pkgid, const std::string& locale) {
543 auto it = pkg_map_.find(pkgid);
544 if (it == pkg_map_.end()) {
545 LOG(ERROR) << "Can not find package from pkg_map";
549 auto& pkg = it->second;
550 pkgmgrinfo_filter_x tmp_filter = { 0, };
551 pkgmgrinfo_node_x node = {
552 .prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE,
553 .value = pkg->package
556 tmp_filter.cache_flag = true;
557 tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
559 std::vector<std::shared_ptr<application_x>> app_list;
560 internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
562 for (auto& appid : pkg_app_map_[pkgid]) {
563 app_map_.erase(appid);
565 pkg_app_map_.erase(pkgid);
567 for (auto& app : app_list) {
568 app->privileges = pkg->privileges;
569 std::string appid = app->appid;
570 AddApplication(std::move(appid), std::move(app));
573 g_slist_free(tmp_filter.list);
577 } // namespace database
578 } // namespace pkgmgr_server