Minor refactor
[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/types.h>
22
23 #include <tzplatform_config.h>
24
25 #include <algorithm>
26 #include <string>
27 #include <vector>
28
29 #include "cache_flag.hh"
30 #include "utils/logging.hh"
31
32 #include "pkgmgr-info.h"
33 #include "pkgmgrinfo_debug.h"
34 #include "pkgmgrinfo_internal.h"
35 #include "pkgmgrinfo_private.h"
36
37 #ifdef LOG_TAG
38 #undef LOG_TAG
39 #endif
40 #define LOG_TAG "PKGMGR_INFO"
41
42 namespace {
43
44 uid_t globaluser_uid = -1;
45
46 uid_t GetGlobalUID() {
47   if (globaluser_uid == (uid_t)-1)
48     globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
49
50   return globaluser_uid;
51 }
52
53 uid_t ConvertUID(uid_t uid) {
54   if (uid < REGULAR_USER)
55     return GetGlobalUID();
56   else
57     return uid;
58 }
59
60 static const std::string global_parser_memdb_path =
61     "file:parserdb?mode=memory&cache=shared";
62
63 static const std::string cert_memdb_path =
64     "file:certdb?mode=memory&cache=shared";
65
66 }  // namespace
67
68 namespace pkgmgr_server {
69 namespace database {
70
71 std::unordered_map<uid_t, std::unique_ptr<DBHandleProvider>>
72     DBHandleProvider::provider_map_;
73 bool DBHandleProvider::is_global_memdb_set_ = false;
74 std::unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
75     DBHandleProvider::global_parser_memdb_handle_(nullptr,
76                                                   sqlite3_close_v2);
77 std::unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
78     DBHandleProvider::cert_memdb_handle_(nullptr, sqlite3_close_v2);
79 std::string DBHandleProvider::global_parser_filedb_path_;
80 std::string DBHandleProvider::cert_filedb_path_;
81 std::unordered_set<pid_t> DBHandleProvider::writer_pid_list_;
82 std::recursive_mutex DBHandleProvider::lock_;
83 std::mutex DBHandleProvider::pid_list_lock_;
84
85 DBHandleProvider::DBHandleProvider(uid_t uid)
86     : uid_(uid),
87       is_user_memdb_set_(false),
88       parser_memdb_handle_(nullptr, sqlite3_close_v2) {
89   char* tmp_path;
90
91   if (global_parser_filedb_path_.empty()) {
92     tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
93     global_parser_filedb_path_ = tmp_path;
94     free(tmp_path);
95   }
96
97   if (cert_filedb_path_.empty()) {
98     tmp_path = getUserPkgCertDBPath();
99     cert_filedb_path_ = tmp_path;
100     free(tmp_path);
101   }
102
103   tmp_path = getUserPkgParserDBPathUID(uid_);
104   user_parser_filedb_path_ = tmp_path;
105   free(tmp_path);
106
107   user_parser_memdb_path_ = "file:parserdb" +
108                             std::to_string(static_cast<int>(uid_)) +
109                             "?mode=memory&cache=shared";
110 }
111
112 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
113   static std::mutex singleton_lock_;
114   std::unique_lock<std::mutex> u(singleton_lock_);
115
116   uid = ConvertUID(uid);
117   auto& prov = provider_map_[uid];
118   if (prov == nullptr)
119     prov.reset(new DBHandleProvider(uid));
120
121   return *prov;
122 }
123
124 bool DBHandleProvider::IsCrashedWriteRequest() {
125   std::unique_lock<std::mutex> u(pid_list_lock_);
126
127   if (writer_pid_list_.empty())
128     return false;
129
130   bool ret = true;
131   LOG(DEBUG) << "Check process count : " << writer_pid_list_.size();
132   std::vector<pid_t> remove_pids;
133   for (pid_t pid : writer_pid_list_) {
134     std::string status_path = "/proc/" + std::to_string(pid) + "/status";
135
136     int fd = open(status_path.c_str(), O_RDONLY);
137     if (fd < 0) {
138       LOG(ERROR) << "Process is crashed : " << pid;
139       remove_pids.push_back(pid);
140     } else {
141       ret = false;
142       close(fd);
143     }
144   }
145
146   for (pid_t pid : remove_pids)
147     writer_pid_list_.erase(pid);
148
149   return ret;
150 }
151
152 std::vector<std::pair<std::string, uid_t>> DBHandleProvider::GetParserDBPath(
153     pid_t pid, bool write) {
154   std::unique_lock<std::recursive_mutex> u(lock_);
155   std::vector<std::pair<std::string, uid_t>> db_path_list;
156
157   if (is_user_memdb_set_ != is_global_memdb_set_)
158     is_global_memdb_set_ ? SetMemoryMode(pid) : UnsetMemoryMode(pid);
159
160   if (IsMemoryDBActive(pid, write)) {
161     if (uid_ > REGULAR_USER)
162       db_path_list.emplace_back(std::make_pair(user_parser_memdb_path_, uid_));
163
164     db_path_list.emplace_back(
165         std::make_pair(global_parser_memdb_path, GetGlobalUID()));
166   } else {
167     if (uid_ > REGULAR_USER)
168       db_path_list.emplace_back(std::make_pair(user_parser_filedb_path_, uid_));
169
170     db_path_list.emplace_back(
171         std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
172   }
173
174   if (db_path_list.size() == 1) {
175     LOG(DEBUG) << "global db path : " << db_path_list[0].first;
176   } else {
177     LOG(DEBUG) << "local db path : " << db_path_list[0].first;
178     LOG(DEBUG) << "global db path : " << db_path_list[1].first;
179   }
180
181   return db_path_list;
182 }
183
184 std::string DBHandleProvider::GetCertDBPath(pid_t pid, bool write) {
185   std::unique_lock<std::recursive_mutex> u(lock_);
186   if (is_user_memdb_set_ != is_global_memdb_set_)
187     is_global_memdb_set_ ? SetMemoryMode(pid) : UnsetMemoryMode(pid);
188
189   if (IsMemoryDBActive(pid, write))
190     return cert_memdb_path;
191   else
192     return cert_filedb_path_;
193 }
194
195 sqlite3* DBHandleProvider::CreateMemoryDBHandle(const std::string& filedb_path,
196                                              const std::string& memorydb_path) {
197   sqlite3* memorydb = nullptr;
198   sqlite3* filedb = nullptr;
199   int ret = sqlite3_open_v2(memorydb_path.c_str(), &memorydb,
200                             SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, nullptr);
201   if (ret != SQLITE_OK) {
202     LOG(ERROR) << "Failed to open memory DB " << ret << ": " << memorydb_path;
203     return nullptr;
204   }
205
206   ret = sqlite3_open_v2(filedb_path.c_str(), &filedb, SQLITE_OPEN_READONLY,
207                         nullptr);
208   if (ret != SQLITE_OK) {
209     LOG(ERROR) << "Failed to open file DB " << ret << ": " << filedb_path;
210     sqlite3_close_v2(memorydb);
211     return nullptr;
212   }
213
214   sqlite3_backup* backup =
215       sqlite3_backup_init(memorydb, "main", filedb, "main");
216   if (backup == nullptr) {
217     LOG(ERROR) << "Failed to backup for memory DB";
218     sqlite3_close_v2(memorydb);
219     sqlite3_close_v2(filedb);
220     return nullptr;
221   }
222
223   sqlite3_backup_step(backup, -1);
224   sqlite3_backup_finish(backup);
225   sqlite3_close_v2(filedb);
226   return memorydb;
227 }
228
229 void DBHandleProvider::SetMemoryMode(pid_t pid) {
230   std::unique_lock<std::recursive_mutex> u(lock_);
231   if (is_global_memdb_set_ && is_user_memdb_set_)
232     return;
233
234   sqlite3* parser_db =
235       CreateMemoryDBHandle(user_parser_filedb_path_, user_parser_memdb_path_);
236   if (parser_db != nullptr)
237     parser_memdb_handle_.reset(parser_db);
238
239   if (is_user_memdb_set_ == is_global_memdb_set_) {
240     sqlite3* global_parser_file_db = CreateMemoryDBHandle(
241         global_parser_filedb_path_, global_parser_memdb_path);
242     if (global_parser_file_db)
243       global_parser_memdb_handle_.reset(global_parser_file_db);
244
245     sqlite3* cert_db =
246         CreateMemoryDBHandle(cert_filedb_path_, cert_memdb_path);
247     if (cert_db != nullptr)
248       cert_memdb_handle_.reset(cert_db);
249
250     InsertPID(pid);
251   }
252
253   is_user_memdb_set_ = true;
254   is_global_memdb_set_ = true;
255   LOG(DEBUG) << "Set Memory mode : Memory";
256 }
257
258 void DBHandleProvider::UnsetMemoryMode(pid_t pid) {
259   std::unique_lock<std::recursive_mutex> u(lock_);
260   if (!is_global_memdb_set_ && !is_user_memdb_set_)
261     return;
262
263   parser_memdb_handle_.reset(nullptr);
264   cert_memdb_handle_.reset(nullptr);
265   global_parser_memdb_handle_.reset(nullptr);
266
267   if (!ErasePID(pid))
268     LOG(ERROR) << "Given pid is not exists in pid list : " << pid;
269
270   is_user_memdb_set_ = false;
271   is_global_memdb_set_ = false;
272
273   auto lock = CacheFlag::GetWriterLock();
274   CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
275
276   pkg_map_.clear();
277   app_map_.clear();
278   CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
279   LOG(DEBUG) << "Set Memory mode : File";
280 }
281
282 bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) {
283   std::unique_lock<std::mutex> u(pid_list_lock_);
284   if (!is_user_memdb_set_)
285     return false;
286
287   if (write)
288     return false;
289
290   if (writer_pid_list_.find(pid) != writer_pid_list_.end())
291     return false;
292
293   return true;
294 }
295
296 void DBHandleProvider::TrimCache() {
297   std::unique_lock<std::recursive_mutex> u(lock_);
298   if (!released_)
299     ReleaseCache();
300 }
301
302 void DBHandleProvider::ReleaseCache() {
303   auto lock = CacheFlag::GetWriterLock();
304   CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
305
306   app_map_.clear();
307   pkg_map_.clear();
308   CacheFlag::SetStatus(CacheFlag::Status::UNPREPARED);
309
310   released_ = true;
311 }
312
313 bool DBHandleProvider::IsWriter(pid_t pid) {
314   std::unique_lock<std::mutex> u(pid_list_lock_);
315   return writer_pid_list_.find(pid) != writer_pid_list_.end();
316 }
317
318 int DBHandleProvider::UpdateCache(sqlite3* db, pid_t pid, uid_t uid, bool write,
319     const std::string& locale) {
320   pkg_map_.clear();
321   app_map_.clear();
322
323   GHashTable* list = g_hash_table_new(g_str_hash, g_str_equal);
324   if (list == nullptr) {
325     LOG(ERROR) << "Out of memory";
326     return PMINFO_R_ERROR;
327   }
328
329   auto tmp_filter = reinterpret_cast<pkgmgrinfo_filter_x*>(
330       calloc(1, sizeof(pkgmgrinfo_filter_x)));
331   if (tmp_filter == nullptr) {
332     LOG(ERROR) << "Out of memory";
333     g_hash_table_destroy(list);
334     return PMINFO_R_ERROR;
335   }
336
337   int ret = pkginfo_internal_filter_get_list(db, tmp_filter, uid_,
338                                              locale.c_str(), list);
339   if (ret == PMINFO_R_OK) {
340     GHashTableIter iter;
341     gpointer value;
342     g_hash_table_iter_init(&iter, list);
343     while (g_hash_table_iter_next(&iter, nullptr, &value)) {
344       auto* pkg = reinterpret_cast<package_x*>(value);
345       AddPackage(pkg->package, pkg);
346     }
347   }
348
349   g_hash_table_destroy(list);
350   if (ret == PMINFO_R_ERROR) {
351     free(tmp_filter);
352     return ret;
353   }
354
355   list = g_hash_table_new(g_str_hash, g_str_equal);
356   ret = appinfo_internal_filter_get_list(db, tmp_filter, uid_, uid,
357                                          locale.c_str(), list);
358   free(tmp_filter);
359   if (ret == PMINFO_R_OK) {
360     GHashTableIter iter;
361     gpointer value;
362     g_hash_table_iter_init(&iter, list);
363     while (g_hash_table_iter_next(&iter, nullptr, &value)) {
364       auto* app = reinterpret_cast<application_x*>(value);
365       app->privileges = pkg_map_[app->package].front()->privileges;
366       AddApplication(app->appid, app);
367     }
368   }
369   g_hash_table_destroy(list);
370   released_ = false;
371
372   return ret;
373 }
374
375 std::vector<std::shared_ptr<package_x>> DBHandleProvider::GetPackages(
376     pid_t pid, bool write, pkgmgrinfo_filter_x* filter,
377     const std::string& package) {
378   std::vector<std::shared_ptr<package_x>> ret;
379   for (auto& info : pkg_map_[package]) {
380     bool pass = true;
381     for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
382       auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
383       auto* checker = FilterCheckerProvider::GetInst().
384           GetPkgFilterChecker(node->prop);
385       if (!checker->CheckFilter(node, info.get())) {
386         pass = false;
387         break;
388       }
389     }
390     if (pass)
391       ret.push_back(info);
392   }
393
394   return ret;
395 }
396
397 void DBHandleProvider::AddPackage(std::string package, package_x* info) {
398   auto ptr = std::shared_ptr<package_x>(info, pkgmgrinfo_basic_free_package);
399   pkg_map_[package].push_back(ptr);
400   pkg_map_[""].push_back(std::move(ptr));
401 }
402
403 std::vector<std::shared_ptr<application_x>> DBHandleProvider::GetApplications(
404     pid_t pid, bool write, pkgmgrinfo_filter_x* filter,
405     const std::string& app) {
406   /* make metadata filter map */
407   std::unordered_map<std::string, std::string> metadata_map;
408   for (auto* it = filter->list_metadata; it != nullptr; it = g_slist_next(it)) {
409     auto node = reinterpret_cast<pkgmgrinfo_metadata_node_x*>(it->data);
410     if (node->key == nullptr)
411       continue;
412
413     metadata_map[node->key] = (node->value ? node->value : "");
414   }
415
416   std::vector<std::shared_ptr<application_x>> ret;
417   for (auto& info : app_map_[app]) {
418     bool pass = true;
419     for (auto* it = filter->list; it != nullptr; it = g_slist_next(it)) {
420       auto node = reinterpret_cast<pkgmgrinfo_node_x*>(it->data);
421       auto* checker = FilterCheckerProvider::GetInst().
422           GetAppFilterChecker(node->prop);
423       if (!checker->CheckFilter(node, info.get())) {
424         pass = false;
425         break;
426       }
427     }
428     if (!pass)
429       continue;
430
431     if (!metadata_map.empty()) {
432       pass = false;
433       for (auto* it = info->metadata; it != nullptr; it = g_list_next(it)) {
434         auto* node = reinterpret_cast<metadata_x*>(it->data);
435         if (node->key != nullptr) {
436           auto metadata = metadata_map.find(node->key);
437           if (metadata != metadata_map.end() &&
438               strstr(node->value ? node->value : "",
439                   metadata->second.c_str()) != nullptr) {
440             pass = true;
441             break;
442           }
443         }
444       }
445     }
446
447     if (pass)
448       ret.push_back(info);
449   }
450   return ret;
451 }
452
453 void DBHandleProvider::AddApplication(std::string app, application_x* info) {
454   auto ptr =
455       std::shared_ptr<application_x>(info, pkgmgrinfo_basic_free_application);
456   app_map_[app].push_back(ptr);
457   app_map_[""].push_back(std::move(ptr));
458 }
459
460 void DBHandleProvider::InsertPID(pid_t pid) {
461   std::unique_lock<std::mutex> u(pid_list_lock_);
462
463   writer_pid_list_.insert(pid);
464 }
465
466 bool DBHandleProvider::ErasePID(pid_t pid) {
467   std::unique_lock<std::mutex> u(pid_list_lock_);
468
469   return writer_pid_list_.erase(pid) == 1;
470 }
471
472 }  // namespace database
473 }  // namespace pkgmgr_server