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