Remove lock when getting the path of the database
[platform/core/appfw/pkgmgr-info.git] / src / server / database / db_handle_provider.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "db_handle_provider.hh"
18
19 #include <fcntl.h>
20 #include <glib.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23
24 #include <tzplatform_config.h>
25
26 #include <algorithm>
27 #include <string>
28 #include <vector>
29
30 #include "cache_flag.hh"
31 #include "utils/logging.hh"
32
33 #include "pkgmgr-info.h"
34 #include "pkgmgrinfo_debug.h"
35 #include "pkgmgrinfo_internal.h"
36 #include "pkgmgrinfo_private.h"
37
38 #ifdef LOG_TAG
39 #undef LOG_TAG
40 #endif
41 #define LOG_TAG "PKGMGR_INFO"
42
43 namespace {
44
45 uid_t globaluser_uid = -1;
46
47 uid_t GetGlobalUID() {
48   if (globaluser_uid == (uid_t)-1)
49     globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
50
51   return globaluser_uid;
52 }
53
54 uid_t ConvertUID(uid_t uid) {
55   if (uid < REGULAR_USER)
56     return GetGlobalUID();
57   else
58     return uid;
59 }
60
61 bool GetModifiedTime(const char* dbpath, timespec* t) {
62   if (dbpath == nullptr || t == nullptr) {
63     LOG(ERROR) << "Invalid argument";
64     return false;
65   }
66
67   struct stat attr;
68   if (stat(dbpath, &attr)) {
69     LOG(ERROR) << "Fail to get status from file "
70         << dbpath << " errno : " << errno;
71     return false;
72   }
73
74   *t = attr.st_mtim;
75
76   return true;
77 }
78
79 }  // namespace
80
81 namespace pkgmgr_server {
82 namespace database {
83
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_;
90
91 DBHandleProvider::DBHandleProvider(uid_t uid) : uid_(uid) {
92   char* tmp_path;
93
94   if (global_parser_filedb_path_.empty()) {
95     tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
96     global_parser_filedb_path_ = tmp_path;
97     free(tmp_path);
98   }
99
100   if (cert_filedb_path_.empty()) {
101     tmp_path = getUserPkgCertDBPath();
102     cert_filedb_path_ = tmp_path;
103     free(tmp_path);
104   }
105
106   tmp_path = getUserPkgParserDBPathUID(uid_);
107   user_parser_filedb_path_ = tmp_path;
108   free(tmp_path);
109 }
110
111 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
112   static std::shared_mutex singleton_lock_;
113   std::shared_lock<std::shared_mutex> s(singleton_lock_);
114
115   uid = ConvertUID(uid);
116   auto it = provider_map_.find(uid);
117   if (it != provider_map_.end())
118     return *(it->second);
119
120   s.unlock();
121   std::unique_lock<std::shared_mutex> u(singleton_lock_);
122   auto& prov = provider_map_[uid];
123   if (prov == nullptr)
124     prov.reset(new DBHandleProvider(uid));
125
126   return *prov;
127 }
128
129 bool DBHandleProvider::IsCrashedWriteRequest() {
130   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
131
132   if (writer_pid_list_.empty())
133     return false;
134
135   bool ret = true;
136   LOG(DEBUG) << "Check process count : " << writer_pid_list_.size();
137   std::vector<pid_t> remove_pids;
138   for (pid_t pid : writer_pid_list_) {
139     std::string status_path = "/proc/" + std::to_string(pid) + "/status";
140
141     int fd = open(status_path.c_str(), O_RDONLY);
142     if (fd < 0) {
143       LOG(ERROR) << "Process is crashed : " << pid;
144       remove_pids.push_back(pid);
145     } else {
146       ret = false;
147       close(fd);
148     }
149   }
150
151   for (pid_t pid : remove_pids)
152     writer_pid_list_.erase(pid);
153
154   return ret;
155 }
156
157 std::vector<std::pair<std::string, uid_t>> DBHandleProvider::GetParserDBPath() {
158   std::vector<std::pair<std::string, uid_t>> db_path_list;
159
160   if (uid_ > REGULAR_USER)
161     db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_));
162
163   db_path_list.emplace_back(
164       std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
165
166   if (db_path_list.size() == 1) {
167     LOG(DEBUG) << "global db path : " << db_path_list[0].first;
168   } else {
169     LOG(DEBUG) << "local db path : " << db_path_list[0].first;
170     LOG(DEBUG) << "global db path : " << db_path_list[1].first;
171   }
172
173   return db_path_list;
174 }
175
176 std::string DBHandleProvider::GetCertDBPath() {
177   return cert_filedb_path_;
178 }
179
180 void DBHandleProvider::TrimCache() {
181   if (!released_)
182     ReleaseCache();
183 }
184
185 void DBHandleProvider::ReleaseCache() {
186   auto lock = CacheFlag::GetWriterLock();
187   CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
188
189   app_map_.clear();
190   pkg_map_.clear();
191   pending_pkg_.clear();
192   pkg_app_map_.clear();
193   CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
194
195   released_ = true;
196 }
197
198 bool DBHandleProvider::IsWriter(pid_t pid) {
199   std::unique_lock<std::shared_mutex> s(pid_list_lock_);
200   return writer_pid_list_.find(pid) != writer_pid_list_.end();
201 }
202
203 int DBHandleProvider::UpdateCache(const tizen_base::Database& db, pid_t pid,
204     uid_t uid, bool write, const std::string& locale) {
205   pkg_map_.clear();
206   app_map_.clear();
207   pending_pkg_.clear();
208   pkg_app_map_.clear();
209
210   const char* dbpath = sqlite3_db_filename(db.GetRaw(), "main");
211
212   timespec start_time = { 0, };
213   timespec end_time = { 0, };
214   if (!GetModifiedTime(dbpath, &start_time))
215     return PMINFO_R_ERROR;
216
217   pkgmgrinfo_filter_x tmp_filter = { 0, };
218   tmp_filter.cache_flag = true;
219   std::map<std::string, std::shared_ptr<package_x>> pkgs;
220   int ret = internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
221   if (ret == PMINFO_R_OK) {
222     for (auto& [key, val] : pkgs)
223       AddPackage(std::move(key), std::move(val));
224   }
225
226   if (!GetModifiedTime(dbpath, &end_time))
227     return PMINFO_R_ERROR;
228
229   if (start_time.tv_sec != end_time.tv_sec ||
230       start_time.tv_nsec != end_time.tv_nsec) {
231     LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
232     return PMINFO_R_ERROR;
233   }
234
235   std::vector<std::shared_ptr<application_x>> app_list;
236   ret = internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
237
238   if (!GetModifiedTime(dbpath, &end_time))
239     return PMINFO_R_ERROR;
240
241   if (start_time.tv_sec != end_time.tv_sec ||
242       start_time.tv_nsec != end_time.tv_nsec) {
243     LOG(ERROR) << "Database(" << dbpath << ") modification was detected";
244     return PMINFO_R_ERROR;
245   }
246
247   if (ret == PMINFO_R_OK) {
248     for (auto& app : app_list) {
249       auto it = pkg_map_.find(app->package);
250       if (it == pkg_map_.end()) {
251         LOG(ERROR) << "Can not find package from pkg_map";
252         return PMINFO_R_ERROR;
253       }
254
255       app->privileges = it->second->privileges;
256       std::string appid = app->appid;
257       AddApplication(std::move(appid), std::move(app));
258     }
259   }
260
261   released_ = false;
262
263   return ret;
264 }
265
266 inline bool CheckMetadataFilter(GList* metadata_list,
267     const std::unordered_map<std::string, std::string>& metadata_map) {
268   for (auto* it = metadata_list; it != nullptr; it = g_list_next(it)) {
269     auto* node = reinterpret_cast<metadata_x*>(it->data);
270     if (node->key != nullptr) {
271       auto metadata = metadata_map.find(node->key);
272       if (metadata == metadata_map.end())
273         continue;
274
275       if (metadata->second.empty() ||
276           strcmp(node->value ? node->value : "", metadata->second.c_str()) == 0)
277         return true;
278     }
279   }
280   return false;
281 }
282
283 inline bool CheckPkgFilters(pkgmgrinfo_filter_x* filter,
284     const std::shared_ptr<package_x>& info,
285     const std::unordered_map<std::string, std::string>& metadata_map) {
286   for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
287     auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
288     auto* checker = FilterCheckerProvider::GetInst().
289         GetPkgFilterChecker(node->prop);
290     if (!checker->CheckFilter(node, info.get()))
291       return false;
292   }
293
294   bool pass = true;
295   if (!metadata_map.empty())
296     pass = CheckMetadataFilter(info->metadata, metadata_map);
297
298   return pass;
299 }
300
301 std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
302     pid_t pid, pkgmgrinfo_filter_x* filter,
303     const std::string& package) {
304   std::vector<std::shared_ptr<package_x>> ret;
305
306   /* make metadata filter map */
307   std::unordered_map<std::string, std::string> metadata_map;
308   for (auto* it = filter->list_pkg_metadata; it != nullptr;
309       it = g_slist_next(it)) {
310     auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
311     if (node->key == nullptr)
312       continue;
313     LOG(ERROR) << "add metadata filter";
314     metadata_map[node->key] = (node->value ? node->value : "");
315   }
316
317   if (internal::CheckPackageStorageStatus(filter)) {
318     if (pkgmgrinfo_pkginfo_filter_add_bool(filter,
319         PMINFO_PKGINFO_PROP_PACKAGE_CHECK_STORAGE, true) != PMINFO_R_OK) {
320       LOG(ERROR) << "Fail to add check storage value to filter";
321       return {};
322     }
323   }
324   if (package.empty()) {
325     for (auto& info : pkg_map_) {
326       if (CheckPkgFilters(filter, info.second, metadata_map))
327         ret.push_back(info.second);
328     }
329   } else {
330     auto map_it = pkg_map_.find(package);
331     if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second,
332         metadata_map))
333       ret.push_back(map_it->second);
334   }
335
336   return ret;
337 }
338
339 void DBHandleProvider::AddPackage(std::string package,
340     std::shared_ptr<package_x> info) {
341   pkg_map_[package] = std::move(info);
342 }
343
344 inline bool CheckAppFilters(pkgmgrinfo_filter_x* filter,
345   const std::shared_ptr<application_x>& app_info,
346   const std::shared_ptr<package_x>& pkg_info,
347   const std::unordered_map<std::string, std::string>& metadata_map) {
348   for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
349     auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
350     auto* checker = FilterCheckerProvider::GetInst().
351         GetAppFilterChecker(node->prop);
352     if (!checker->CheckFilter(node, app_info.get(), pkg_info.get()))
353       return false;
354   }
355
356   bool pass = true;
357   if (!metadata_map.empty())
358     pass = CheckMetadataFilter(app_info->metadata, metadata_map);
359   return pass;
360 }
361
362 std::shared_ptr<package_x> DBHandleProvider::GetPackageByApp(
363     const char* appid) {
364   auto it = pkg_map_.find(appid);
365   if (it == pkg_map_.end())
366     return nullptr;
367
368   return it->second;
369 }
370
371 std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
372     pid_t pid, pkgmgrinfo_filter_x* filter,
373     const std::string& app) {
374   /* make metadata filter map */
375   std::unordered_map<std::string, std::string> metadata_map;
376   for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
377     auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
378     if (node->key == nullptr)
379       continue;
380
381     metadata_map[node->key] = (node->value ? node->value : "");
382   }
383
384   std::vector<std::shared_ptr<application_x>> ret;
385   if (internal::CheckAppStorageStatus(filter)) {
386     if (pkgmgrinfo_appinfo_filter_add_bool(filter,
387         PMINFO_APPINFO_PROP_APP_CHECK_STORAGE, true) != PMINFO_R_OK) {
388       LOG(ERROR) << "Fail to add check storage value to filter";
389       return {};
390     }
391   }
392
393   if (app.empty()) {
394     for (auto& info : app_map_) {
395       if (CheckAppFilters(filter, info.second,
396           GetPackageByApp(info.second->package), metadata_map))
397         ret.push_back(info.second);
398     }
399   } else {
400     auto map_it = app_map_.find(app);
401     if (map_it != app_map_.end() &&
402         CheckAppFilters(filter, map_it->second,
403             GetPackageByApp(map_it->second->package), metadata_map))
404       ret.push_back(map_it->second);
405   }
406
407   return ret;
408 }
409
410 void DBHandleProvider::AddApplication(std::string app,
411     std::shared_ptr<application_x> info) {
412   pkg_app_map_[info->package].emplace(app);
413   app_map_[app] = std::move(info);
414 }
415
416 void DBHandleProvider::InsertPID(pid_t pid) {
417   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
418
419   writer_pid_list_.insert(pid);
420 }
421
422 bool DBHandleProvider::ErasePID(pid_t pid) {
423   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
424
425   return writer_pid_list_.erase(pid) == 1;
426 }
427
428 void DBHandleProvider::RegisterPendingPackageInfo(package_x* info) {
429   if (!info || !info->package)
430     return;
431
432   pending_pkg_.emplace(info->package);
433 }
434
435 void DBHandleProvider::UpdatePendingPackageInfo(const tizen_base::Database& db,
436     pid_t pid, uid_t uid, const std::string& locale) {
437   pkgmgrinfo_filter_x tmp_filter = { 0, };
438   pkgmgrinfo_node_x node = {
439     .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID
440   };
441   tmp_filter.cache_flag = true;
442   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
443   std::map<std::string, std::shared_ptr<package_x>> pkgs;
444   for (const auto& pkg : pending_pkg_) {
445     pkg_map_.erase(pkg);
446     for (auto& appid : pkg_app_map_[pkg]) {
447       app_map_.erase(appid);
448     }
449
450     pkg_app_map_.erase(pkg);
451     node.value = const_cast<char*>(pkg.c_str());
452     internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
453   }
454
455   for (auto& [key, val] : pkgs)
456     AddPackage(key, val);
457
458   node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
459   for (auto& [key, val] : pkgs) {
460     node.value = val->package;
461     std::vector<std::shared_ptr<application_x>> app_list;
462     internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
463
464     for (auto& app : app_list) {
465       app->privileges = val->privileges;
466       std::string appid = app->appid;
467       AddApplication(std::move(appid), std::move(app));
468     }
469   }
470
471   g_slist_free(tmp_filter.list);
472   pending_pkg_.clear();
473 }
474
475 bool DBHandleProvider::UpdateCachePkg(const tizen_base::Database& db, uid_t uid,
476     const std::string& pkgid, const std::string& locale) {
477   pkgmgrinfo_filter_x tmp_filter = { 0, };
478   pkgmgrinfo_node_x node = {
479     .prop = E_PMINFO_PKGINFO_PROP_PACKAGE_ID,
480     .value = const_cast<char*>(pkgid.c_str())
481   };
482   tmp_filter.cache_flag = true;
483   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
484   std::map<std::string, std::shared_ptr<package_x>> pkgs;
485   internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
486   for (auto& [key, val] : pkgs) {
487     AddPackage(key, val);
488     for (auto& appid : pkg_app_map_[key]) {
489       app_map_.erase(appid);
490     }
491
492     pkg_app_map_.erase(key);
493     std::vector<std::shared_ptr<application_x>> app_list;
494     node.prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE;
495     node.value = const_cast<char*>(key.c_str());
496     internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
497     for (auto& app : app_list) {
498       app->privileges = val->privileges;
499       std::string appid = app->appid;
500       AddApplication(std::move(appid), std::move(app));
501     }
502   }
503
504   return true;
505 }
506
507 bool DBHandleProvider::UpdateCacheApp(const tizen_base::Database& db, uid_t uid,
508     const std::string& appid, const std::string& locale) {
509   pkgmgrinfo_filter_x tmp_filter = { 0, };
510   pkgmgrinfo_node_x node = {
511     .prop = E_PMINFO_APPINFO_PROP_APP_ID,
512     .value = const_cast<char*>(appid.c_str())
513   };
514   tmp_filter.cache_flag = true;
515   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
516
517   std::vector<std::shared_ptr<application_x>> app_list;
518   app_map_.erase(appid);
519   internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
520   g_slist_free(tmp_filter.list);
521
522   for (auto& app : app_list) {
523     auto it = pkg_map_.find(app->package);
524     if (it == pkg_map_.end()) {
525       LOG(ERROR) << "Can not find package from pkg_map";
526       return false;
527     }
528
529     pkg_app_map_[app->package].erase(app->appid);
530     app->privileges = it->second->privileges;
531     std::string appid = app->appid;
532     AddApplication(std::move(appid), std::move(app));
533   }
534
535   return true;
536 }
537
538 bool DBHandleProvider::UpdateCacheAppByPkgid(const tizen_base::Database& db,
539     uid_t uid, const std::string& pkgid, const std::string& locale) {
540   auto it = pkg_map_.find(pkgid);
541   if (it == pkg_map_.end()) {
542     LOG(ERROR) << "Can not find package from pkg_map";
543     return false;
544   }
545
546   auto& pkg = it->second;
547   pkgmgrinfo_filter_x tmp_filter = { 0, };
548   pkgmgrinfo_node_x node = {
549     .prop = E_PMINFO_APPINFO_PROP_APP_PACKAGE,
550     .value = pkg->package
551   };
552
553   tmp_filter.cache_flag = true;
554   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
555
556   std::vector<std::shared_ptr<application_x>> app_list;
557   internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
558
559   for (auto& appid : pkg_app_map_[pkgid]) {
560     app_map_.erase(appid);
561   }
562   pkg_app_map_.erase(pkgid);
563
564   for (auto& app : app_list) {
565     app->privileges = pkg->privileges;
566     std::string appid = app->appid;
567     AddApplication(std::move(appid), std::move(app));
568   }
569
570   g_slist_free(tmp_filter.list);
571   return true;
572 }
573
574 }  // namespace database
575 }  // namespace pkgmgr_server