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_provider.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(
170           std::make_pair(user_parser_filedb_path_, uid_));
171     }
172
173     db_path_list.emplace_back(
174         std::make_pair(global_parser_filedb_path_, GetGlobalUID()));
175   }
176
177   if (db_path_list.size() == 1) {
178     LOG(DEBUG) << "global db path : " << db_path_list[0].first;
179   } else {
180     LOG(DEBUG) << "local db path : " << db_path_list[0].first;
181     LOG(DEBUG) << "global db path : " << db_path_list[1].first;
182   }
183
184   return db_path_list;
185 }
186
187 std::string DBHandleProvider::GetCertDBPath(pid_t pid, bool write) {
188   std::unique_lock<std::recursive_mutex> u(lock_);
189   if (is_user_memdb_set_ != is_global_memdb_set_)
190     is_global_memdb_set_ ? SetMemoryMode(pid) : UnsetMemoryMode(pid);
191
192   if (IsMemoryDBActive(pid, write))
193     return cert_memdb_path;
194   else
195     return cert_filedb_path_;
196 }
197
198 sqlite3* DBHandleProvider::CreateMemoryDBHandle(const std::string& filedb_path,
199     const std::string& memorydb_path) {
200   sqlite3* memorydb = nullptr;
201   sqlite3* filedb = nullptr;
202   int ret = sqlite3_open_v2(memorydb_path.c_str(), &memorydb,
203                             SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, nullptr);
204   if (ret != SQLITE_OK) {
205     LOG(ERROR) << "Failed to open memory DB " << ret << ": " << memorydb_path;
206     return nullptr;
207   }
208
209   ret = sqlite3_open_v2(filedb_path.c_str(), &filedb, SQLITE_OPEN_READONLY,
210                         nullptr);
211   if (ret != SQLITE_OK) {
212     LOG(ERROR) << "Failed to open file DB " << ret << ": " << filedb_path;
213     sqlite3_close_v2(memorydb);
214     return nullptr;
215   }
216
217   sqlite3_backup* backup =
218       sqlite3_backup_init(memorydb, "main", filedb, "main");
219   if (backup == nullptr) {
220     LOG(ERROR) << "Failed to backup for memory DB";
221     sqlite3_close_v2(memorydb);
222     sqlite3_close_v2(filedb);
223     return nullptr;
224   }
225
226   sqlite3_backup_step(backup, -1);
227   sqlite3_backup_finish(backup);
228   sqlite3_close_v2(filedb);
229   return memorydb;
230 }
231
232 void DBHandleProvider::SetMemoryMode(pid_t pid) {
233   std::unique_lock<std::recursive_mutex> u(lock_);
234   if (is_global_memdb_set_ && is_user_memdb_set_)
235     return;
236
237   sqlite3* parser_db =
238       CreateMemoryDBHandle(user_parser_filedb_path_, user_parser_memdb_path_);
239   if (parser_db != nullptr)
240     parser_memdb_handle_.reset(parser_db);
241
242   if (is_user_memdb_set_ == is_global_memdb_set_) {
243     sqlite3* global_parser_file_db = CreateMemoryDBHandle(
244         global_parser_filedb_path_, global_parser_memdb_path);
245     if (global_parser_file_db)
246       global_parser_memdb_handle_.reset(global_parser_file_db);
247
248     sqlite3* cert_db =
249         CreateMemoryDBHandle(cert_filedb_path_, cert_memdb_path);
250     if (cert_db != nullptr)
251       cert_memdb_handle_.reset(cert_db);
252
253     InsertPID(pid);
254   }
255
256   is_user_memdb_set_ = true;
257   is_global_memdb_set_ = true;
258   LOG(DEBUG) << "Set Memory mode : Memory";
259 }
260
261 void DBHandleProvider::UnsetMemoryMode(pid_t pid) {
262   std::unique_lock<std::recursive_mutex> u(lock_);
263   if (!is_global_memdb_set_ && !is_user_memdb_set_)
264     return;
265
266   parser_memdb_handle_.reset(nullptr);
267   cert_memdb_handle_.reset(nullptr);
268   global_parser_memdb_handle_.reset(nullptr);
269
270   if (!ErasePID(pid))
271     LOG(ERROR) << "Given pid is not exists in pid list : " << pid;
272
273   is_user_memdb_set_ = false;
274   is_global_memdb_set_ = false;
275
276   CacheProvider provider(uid_);
277   provider.ReleaseCache();
278
279   if (ConvertUID(uid_) != GetGlobalUID())
280     CacheProvider(GetGlobalUID()).ReleaseCache();
281
282   LOG(DEBUG) << "Set Memory mode : File";
283 }
284
285 bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) {
286   std::unique_lock<std::mutex> u(pid_list_lock_);
287   if (!is_user_memdb_set_)
288     return false;
289
290   if (write)
291     return false;
292
293   if (writer_pid_list_.find(pid) != writer_pid_list_.end())
294     return false;
295
296   return true;
297 }
298
299 bool DBHandleProvider::IsWriter(pid_t pid) {
300   std::unique_lock<std::mutex> u(pid_list_lock_);
301   return writer_pid_list_.find(pid) != writer_pid_list_.end();
302 }
303
304 void DBHandleProvider::InsertPID(pid_t pid) {
305   std::unique_lock<std::mutex> u(pid_list_lock_);
306
307   writer_pid_list_.insert(pid);
308 }
309
310 bool DBHandleProvider::ErasePID(pid_t pid) {
311   std::unique_lock<std::mutex> u(pid_list_lock_);
312
313   return writer_pid_list_.erase(pid) == 1;
314 }
315
316 }  // namespace database
317 }  // namespace pkgmgr_server