Remove the memory database for the cache
[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::recursive_mutex DBHandleProvider::lock_;
90 std::shared_mutex DBHandleProvider::pid_list_lock_;
91
92 DBHandleProvider::DBHandleProvider(uid_t uid) : uid_(uid) {
93   char* tmp_path;
94
95   if (global_parser_filedb_path_.empty()) {
96     tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
97     global_parser_filedb_path_ = tmp_path;
98     free(tmp_path);
99   }
100
101   if (cert_filedb_path_.empty()) {
102     tmp_path = getUserPkgCertDBPath();
103     cert_filedb_path_ = tmp_path;
104     free(tmp_path);
105   }
106
107   tmp_path = getUserPkgParserDBPathUID(uid_);
108   user_parser_filedb_path_ = tmp_path;
109   free(tmp_path);
110 }
111
112 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
113   static std::shared_mutex singleton_lock_;
114   std::shared_lock<std::shared_mutex> s(singleton_lock_);
115
116   uid = ConvertUID(uid);
117   auto it = provider_map_.find(uid);
118   if (it != provider_map_.end())
119     return *(it->second);
120
121   s.unlock();
122   std::unique_lock<std::shared_mutex> u(singleton_lock_);
123   auto& prov = provider_map_[uid];
124   if (prov == nullptr)
125     prov.reset(new DBHandleProvider(uid));
126
127   return *prov;
128 }
129
130 bool DBHandleProvider::IsCrashedWriteRequest() {
131   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
132
133   if (writer_pid_list_.empty())
134     return false;
135
136   bool ret = true;
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";
141
142     int fd = open(status_path.c_str(), O_RDONLY);
143     if (fd < 0) {
144       LOG(ERROR) << "Process is crashed : " << pid;
145       remove_pids.push_back(pid);
146     } else {
147       ret = false;
148       close(fd);
149     }
150   }
151
152   for (pid_t pid : remove_pids)
153     writer_pid_list_.erase(pid);
154
155   return ret;
156 }
157
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;
161
162   if (uid_ > REGULAR_USER)
163     db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_));
164
165   db_path_list.emplace_back(
166       std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
167
168   if (db_path_list.size() == 1) {
169     LOG(DEBUG) << "global db path : " << db_path_list[0].first;
170   } else {
171     LOG(DEBUG) << "local db path : " << db_path_list[0].first;
172     LOG(DEBUG) << "global db path : " << db_path_list[1].first;
173   }
174
175   return db_path_list;
176 }
177
178 std::string DBHandleProvider::GetCertDBPath() {
179   return cert_filedb_path_;
180 }
181
182 void DBHandleProvider::TrimCache() {
183   std::unique_lock<std::recursive_mutex> u(lock_);
184   if (!released_)
185     ReleaseCache();
186 }
187
188 void DBHandleProvider::ReleaseCache() {
189   auto lock = CacheFlag::GetWriterLock();
190   CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
191
192   app_map_.clear();
193   pkg_map_.clear();
194   pending_pkg_.clear();
195   pkg_app_map_.clear();
196   CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
197
198   released_ = true;
199 }
200
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();
204 }
205
206 int DBHandleProvider::UpdateCache(const tizen_base::Database& db, pid_t pid,
207     uid_t uid, bool write, const std::string& locale) {
208   pkg_map_.clear();
209   app_map_.clear();
210   pending_pkg_.clear();
211   pkg_app_map_.clear();
212
213   const char* dbpath = sqlite3_db_filename(db.GetRaw(), "main");
214
215   timespec start_time = { 0, };
216   timespec end_time = { 0, };
217   if (!GetModifiedTime(dbpath, &start_time))
218     return PMINFO_R_ERROR;
219
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));
227   }
228
229   if (!GetModifiedTime(dbpath, &end_time))
230     return PMINFO_R_ERROR;
231
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;
236   }
237
238   std::vector<std::shared_ptr<application_x>> app_list;
239   ret = internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
240
241   if (!GetModifiedTime(dbpath, &end_time))
242     return PMINFO_R_ERROR;
243
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;
248   }
249
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;
256       }
257
258       app->privileges = it->second->privileges;
259       std::string appid = app->appid;
260       AddApplication(std::move(appid), std::move(app));
261     }
262   }
263
264   released_ = false;
265
266   return ret;
267 }
268
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())
276         continue;
277
278       if (metadata->second.empty() ||
279           strcmp(node->value ? node->value : "", metadata->second.c_str()) == 0)
280         return true;
281     }
282   }
283   return false;
284 }
285
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()))
294       return false;
295   }
296
297   bool pass = true;
298   if (!metadata_map.empty())
299     pass = CheckMetadataFilter(info->metadata, metadata_map);
300
301   return pass;
302 }
303
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;
308
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)
315       continue;
316     LOG(ERROR) << "add metadata filter";
317     metadata_map[node->key] = (node->value ? node->value : "");
318   }
319
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";
324       return {};
325     }
326   }
327   if (package.empty()) {
328     for (auto& info : pkg_map_) {
329       if (CheckPkgFilters(filter, info.second, metadata_map))
330         ret.push_back(info.second);
331     }
332   } else {
333     auto map_it = pkg_map_.find(package);
334     if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second,
335         metadata_map))
336       ret.push_back(map_it->second);
337   }
338
339   return ret;
340 }
341
342 void DBHandleProvider::AddPackage(std::string package,
343     std::shared_ptr<package_x> info) {
344   pkg_map_[package] = std::move(info);
345 }
346
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()))
356       return false;
357   }
358
359   bool pass = true;
360   if (!metadata_map.empty())
361     pass = CheckMetadataFilter(app_info->metadata, metadata_map);
362   return pass;
363 }
364
365 std::shared_ptr<package_x> DBHandleProvider::GetPackageByApp(
366     const char* appid) {
367   auto it = pkg_map_.find(appid);
368   if (it == pkg_map_.end())
369     return nullptr;
370
371   return it->second;
372 }
373
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)
382       continue;
383
384     metadata_map[node->key] = (node->value ? node->value : "");
385   }
386
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";
392       return {};
393     }
394   }
395
396   if (app.empty()) {
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);
401     }
402   } else {
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);
408   }
409
410   return ret;
411 }
412
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);
417 }
418
419 void DBHandleProvider::InsertPID(pid_t pid) {
420   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
421
422   writer_pid_list_.insert(pid);
423 }
424
425 bool DBHandleProvider::ErasePID(pid_t pid) {
426   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
427
428   return writer_pid_list_.erase(pid) == 1;
429 }
430
431 void DBHandleProvider::RegisterPendingPackageInfo(package_x* info) {
432   if (!info || !info->package)
433     return;
434
435   pending_pkg_.emplace(info->package);
436 }
437
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
443   };
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_) {
448     pkg_map_.erase(pkg);
449     for (auto& appid : pkg_app_map_[pkg]) {
450       app_map_.erase(appid);
451     }
452
453     pkg_app_map_.erase(pkg);
454     node.value = const_cast<char*>(pkg.c_str());
455     internal::GetPkgInfo(db, &tmp_filter, uid_, locale, pkgs);
456   }
457
458   for (auto& [key, val] : pkgs)
459     AddPackage(key, val);
460
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);
466
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));
471     }
472   }
473
474   g_slist_free(tmp_filter.list);
475   pending_pkg_.clear();
476 }
477
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())
484   };
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);
493     }
494
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));
504     }
505   }
506
507   return true;
508 }
509
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())
516   };
517   tmp_filter.cache_flag = true;
518   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
519
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);
524
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";
529       return false;
530     }
531
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));
536   }
537
538   return true;
539 }
540
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";
546     return false;
547   }
548
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
554   };
555
556   tmp_filter.cache_flag = true;
557   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
558
559   std::vector<std::shared_ptr<application_x>> app_list;
560   internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
561
562   for (auto& appid : pkg_app_map_[pkgid]) {
563     app_map_.erase(appid);
564   }
565   pkg_app_map_.erase(pkgid);
566
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));
571   }
572
573   g_slist_free(tmp_filter.list);
574   return true;
575 }
576
577 }  // namespace database
578 }  // namespace pkgmgr_server