5576c67b03403c7a93c6efe933c3910958f9cf2c
[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 std::unordered_set<pid_t> DBHandleProvider::CrashedWriteRequestPIDs() {
130   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
131
132   if (writer_pid_list_.empty())
133     return {};
134
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";
139
140     int fd = open(status_path.c_str(), O_RDONLY);
141     if (fd < 0) {
142       LOG(ERROR) << "Process is crashed : " << pid;
143       remove_pids.emplace(pid);
144     } else {
145       close(fd);
146     }
147   }
148
149   return remove_pids;
150 }
151
152 std::vector<std::pair<std::string, uid_t>> DBHandleProvider::GetParserDBPath() {
153   std::vector<std::pair<std::string, uid_t>> db_path_list;
154
155   if (uid_ > REGULAR_USER)
156     db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_));
157
158   db_path_list.emplace_back(
159       std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
160
161   if (db_path_list.size() == 1) {
162     LOG(DEBUG) << "global db path : " << db_path_list[0].first;
163   } else {
164     LOG(DEBUG) << "local db path : " << db_path_list[0].first;
165     LOG(DEBUG) << "global db path : " << db_path_list[1].first;
166   }
167
168   return db_path_list;
169 }
170
171 std::string DBHandleProvider::GetCertDBPath() {
172   return cert_filedb_path_;
173 }
174
175 void DBHandleProvider::TrimCache() {
176   if (!released_)
177     ReleaseCache();
178 }
179
180 void DBHandleProvider::ReleaseCache() {
181   auto lock = CacheFlag::GetWriterLock();
182   CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
183
184   app_map_.clear();
185   pkg_map_.clear();
186   pending_pkg_.clear();
187   pkg_app_map_.clear();
188   CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
189
190   released_ = true;
191 }
192
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();
196 }
197
198 int DBHandleProvider::UpdateCache(const tizen_base::Database& db, pid_t pid,
199     uid_t uid, bool write, const std::string& locale) {
200   pkg_map_.clear();
201   app_map_.clear();
202   pending_pkg_.clear();
203   pkg_app_map_.clear();
204
205   const char* dbpath = sqlite3_db_filename(db.GetRaw(), "main");
206
207   timespec start_time = { 0, };
208   timespec end_time = { 0, };
209   if (!GetModifiedTime(dbpath, &start_time))
210     return PMINFO_R_ERROR;
211
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));
219   }
220
221   if (!GetModifiedTime(dbpath, &end_time))
222     return PMINFO_R_ERROR;
223
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;
228   }
229
230   std::vector<std::shared_ptr<application_x>> app_list;
231   ret = internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
232
233   if (!GetModifiedTime(dbpath, &end_time))
234     return PMINFO_R_ERROR;
235
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;
240   }
241
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;
248       }
249
250       app->privileges = it->second->privileges;
251       AddApplication(std::move(app));
252     }
253   }
254
255   released_ = false;
256
257   return ret;
258 }
259
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())
267         continue;
268
269       if (metadata->second.empty() ||
270           strcmp(node->value ? node->value : "", metadata->second.c_str()) == 0)
271         return true;
272     }
273   }
274   return false;
275 }
276
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()))
285       return false;
286   }
287
288   bool pass = true;
289   if (!metadata_map.empty())
290     pass = CheckMetadataFilter(info->metadata, metadata_map);
291
292   return pass;
293 }
294
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;
299
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)
306       continue;
307     LOG(ERROR) << "add metadata filter";
308     metadata_map[node->key] = (node->value ? node->value : "");
309   }
310
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";
315       return {};
316     }
317   }
318   if (package.empty()) {
319     for (auto& info : pkg_map_) {
320       if (CheckPkgFilters(filter, info.second, metadata_map))
321         ret.push_back(info.second);
322     }
323   } else {
324     auto map_it = pkg_map_.find(package);
325     if (map_it != pkg_map_.end() && CheckPkgFilters(filter, map_it->second,
326         metadata_map))
327       ret.push_back(map_it->second);
328   }
329
330   return ret;
331 }
332
333 void DBHandleProvider::AddPackage(std::shared_ptr<package_x> info) {
334   pkg_map_[info->package] = std::move(info);
335 }
336
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));
342 }
343
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)
348       app_map_.erase(app);
349     pkg_app_map_.erase(it);
350   }
351
352   pkg_map_.erase(pkgid);
353 }
354
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()))
364       return false;
365   }
366
367   bool pass = true;
368   if (!metadata_map.empty())
369     pass = CheckMetadataFilter(app_info->metadata, metadata_map);
370   return pass;
371 }
372
373 std::shared_ptr<package_x> DBHandleProvider::GetPackageByApp(
374     const char* appid) {
375   auto it = pkg_map_.find(appid);
376   if (it == pkg_map_.end())
377     return nullptr;
378
379   return it->second;
380 }
381
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)
390       continue;
391
392     metadata_map[node->key] = (node->value ? node->value : "");
393   }
394
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";
400       return {};
401     }
402   }
403
404   if (app.empty()) {
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);
409     }
410   } else {
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);
416   }
417
418   return ret;
419 }
420
421 void DBHandleProvider::InsertWriterPID(pid_t pid) {
422   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
423
424   writer_pid_list_.insert(pid);
425 }
426
427 bool DBHandleProvider::EraseWriterPID(pid_t pid) {
428   std::unique_lock<std::shared_mutex> u(pid_list_lock_);
429
430   return writer_pid_list_.erase(pid) == 1;
431 }
432
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)
437     return;
438
439   InsertWriterPID(pid);
440
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
445     };
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;
449
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);
457
458       for (auto& app : app_list) {
459         app->privileges = pkg_handle->privileges;
460         pending_app_[pkgid].emplace_back(std::move(app));
461       }
462
463       pending_pkg_[pkgid] = std::make_pair(pid, std::move(pkg_handle));
464     }
465
466     g_slist_free(tmp_filter.list);
467   } else {
468     pending_pkg_[info->package] = std::make_pair(pid, nullptr);
469     pending_app_.erase(info->package);
470   }
471 }
472
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())
478       continue;
479
480     ErasePackage(pkgid);
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);
486     }
487
488     if (pkg_it->second.second)
489       AddPackage(std::move(pkg_it->second.second));
490
491     EraseWriterPID(pkg_it->second.first);
492     pending_pkg_.erase(pkg_it);
493   }
494 }
495
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()) {
501       it++;
502       continue;
503     }
504
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)
509         app_map_.erase(app);
510
511       pkg_app_map_.erase(old_app_it);
512     }
513
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);
519     }
520
521     if (it->second.second)
522       AddPackage(std::move(it->second.second));
523
524     EraseWriterPID(it->second.first);
525     it = pending_pkg_.erase(it);
526   }
527 }
528
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())
535   };
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) {
541     AddPackage(val);
542     for (auto& appid : pkg_app_map_[key])
543       app_map_.erase(appid);
544
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));
553     }
554   }
555
556   return true;
557 }
558
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())
565   };
566   tmp_filter.cache_flag = true;
567   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
568
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);
573
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";
578       return false;
579     }
580
581     pkg_app_map_[app->package].erase(app->appid);
582     app->privileges = it->second->privileges;
583     AddApplication(std::move(app));
584   }
585
586   return true;
587 }
588
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";
594     return false;
595   }
596
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
602   };
603
604   tmp_filter.cache_flag = true;
605   tmp_filter.list = g_slist_append(tmp_filter.list, (gpointer)&node);
606
607   std::vector<std::shared_ptr<application_x>> app_list;
608   internal::GetAppInfo(db, &tmp_filter, uid_, uid, locale, app_list);
609
610   for (auto& appid : pkg_app_map_[pkgid]) {
611     app_map_.erase(appid);
612   }
613   pkg_app_map_.erase(pkgid);
614
615   for (auto& app : app_list) {
616     app->privileges = pkg->privileges;
617     AddApplication(std::move(app));
618   }
619
620   g_slist_free(tmp_filter.list);
621   return true;
622 }
623
624 }  // namespace database
625 }  // namespace pkgmgr_server