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