Cleanup code
[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 <sys/types.h>
21
22 #include <tzplatform_config.h>
23
24 #include <algorithm>
25 #include <string>
26 #include <vector>
27
28 #include "pkgmgrinfo_debug.h"
29 #include "pkgmgr-info.h"
30
31 #ifdef LOG_TAG
32 #undef LOG_TAG
33 #endif
34 #define LOG_TAG "PKGMGR_INFO"
35
36 namespace {
37
38 constexpr uid_t REGULAR_USER = 5000;
39
40 uid_t GetGlobalUID() {
41   return tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
42 }
43
44 uid_t ConvertUID(uid_t uid) {
45   if (uid < REGULAR_USER)
46     return tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
47   else
48     return uid;
49 }
50
51 static const std::string global_parser_memory_db_path =
52     "file:parserdb?mode=memory&cache=shared";
53
54 static const std::string cert_memory_db_path =
55     "file:certdb?mode=memory&cache=shared";
56
57 }  // namespace
58
59 namespace pkgmgr_server {
60 namespace database {
61
62 std::unordered_map<uid_t, std::unique_ptr<DBHandleProvider>>
63     DBHandleProvider::provider_;
64 bool DBHandleProvider::is_memory_global_ = false;
65 std::unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
66     DBHandleProvider::global_parser_memory_db_handle_(
67         nullptr, sqlite3_close_v2);
68 std::unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
69     DBHandleProvider::cert_memory_db_handle_(nullptr, sqlite3_close_v2);
70 std::string DBHandleProvider::global_parser_file_db_path_;
71 std::string DBHandleProvider::cert_file_db_path_;
72 std::unordered_set<pid_t> DBHandleProvider::pid_list_;
73 std::recursive_mutex DBHandleProvider::lock_;
74
75 DBHandleProvider::DBHandleProvider(uid_t uid) : uid_(uid),
76     is_memory_(false), parser_memory_db_handle_(nullptr, sqlite3_close_v2) {
77   char* tmp_path;
78
79   if (global_parser_file_db_path_.empty()) {
80     tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
81     global_parser_file_db_path_ = tmp_path;
82     free(tmp_path);
83
84     tmp_path = getUserPkgCertDBPath();
85     cert_file_db_path_ = tmp_path;
86     free(tmp_path);
87   }
88
89   tmp_path = getUserPkgParserDBPathUID(uid_);
90   parser_file_db_path_ = tmp_path;
91   free(tmp_path);
92
93   parser_memory_db_path_ = "file:parserdb" +
94       std::to_string(static_cast<int>(uid_)) + "?mode=memory&cache=shared";
95 }
96
97 DBHandleProvider& DBHandleProvider::GetInst(uid_t uid) {
98   static std::mutex singleton_lock;
99   std::unique_lock<std::mutex> u(singleton_lock);
100
101   uid = ConvertUID(uid);
102   auto& prov = provider_[uid];
103   if (prov == nullptr)
104     prov.reset(new DBHandleProvider(uid));
105
106   return *prov;
107 }
108
109 bool DBHandleProvider::IsCrashedWriteRequest() {
110   std::unique_lock<std::recursive_mutex> u(lock_);
111
112   if (pid_list_.empty())
113     return false;
114
115   bool ret = true;
116   LOGD("Check process count : %zu", pid_list_.size());
117   std::vector<pid_t> remove_pids;
118   for (pid_t pid : pid_list_) {
119     std::string status_path = "/proc/" + std::to_string(pid) + "/status";
120
121     int fd = open(status_path.c_str(), O_RDONLY);
122     if (fd < 0) {
123       LOGE("Process is crashed (%d)", pid);
124       remove_pids.push_back(pid);
125     } else {
126       ret = false;
127       close(fd);
128     }
129   }
130
131   for (pid_t pid : remove_pids)
132     pid_list_.erase(pid);
133
134   return ret;
135 }
136
137 std::vector<std::pair<std::string, uid_t>> DBHandleProvider::GetParserDBPath(
138     pid_t pid, bool write) {
139   std::unique_lock<std::recursive_mutex> u(lock_);
140   std::vector<std::pair<std::string, uid_t>> db_path_list;
141
142   if (is_memory_ != is_memory_global_)
143     is_memory_global_ ? SetMemoryMode(pid) : UnsetMemoryMode(pid);
144
145   if (IsMemoryDBActive(pid, write)) {
146     if (uid_ > REGULAR_USER)
147       db_path_list.emplace_back(std::make_pair(parser_memory_db_path_, uid_));
148     db_path_list.emplace_back(
149         std::make_pair(global_parser_memory_db_path, GetGlobalUID()));
150   } else {
151     if (uid_ > REGULAR_USER)
152       db_path_list.emplace_back(std::make_pair(parser_file_db_path_, uid_));
153     db_path_list.emplace_back(
154         std::make_pair(global_parser_file_db_path_, GetGlobalUID()));
155   }
156
157   if (db_path_list.size() == 1) {
158     LOGD("global db path : %s", db_path_list[0].first.c_str());
159   } else {
160     LOGD("local db path : %s", db_path_list[0].first.c_str());
161     LOGD("global db path : %s", db_path_list[1].first.c_str());
162   }
163
164   return db_path_list;
165 }
166
167 std::string DBHandleProvider::GetCertDBPath(pid_t pid, bool write) {
168   std::unique_lock<std::recursive_mutex> u(lock_);
169   if (is_memory_ != is_memory_global_)
170     is_memory_global_ ?
171         SetMemoryMode(pid) : UnsetMemoryMode(is_memory_global_);
172
173   if (IsMemoryDBActive(pid, write))
174     return cert_memory_db_path;
175   else
176     return cert_file_db_path_;
177 }
178
179 sqlite3* DBHandleProvider::GetMemoryDBHandle(const std::string& filedb_path,
180     const std::string& memorydb_path) {
181   sqlite3* memorydb = nullptr;
182   sqlite3* filedb = nullptr;
183   int ret = sqlite3_open_v2(memorydb_path.c_str(), &memorydb,
184       SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, nullptr);
185   if (ret != SQLITE_OK) {
186     LOGE("Failed to open memory DB %d(%s)", ret, memorydb_path.c_str());
187     return nullptr;
188   }
189
190   ret = sqlite3_open_v2(filedb_path.c_str(), &filedb,
191       SQLITE_OPEN_READONLY, nullptr);
192   if (ret != SQLITE_OK) {
193     LOGE("Failed to open file DB %d(%s)", ret, filedb_path.c_str());
194     sqlite3_close_v2(memorydb);
195     return nullptr;
196   }
197
198   sqlite3_backup* backup = sqlite3_backup_init(memorydb, "main",
199       filedb, "main");
200   if (backup == nullptr) {
201     LOGE("Failed to backup for memory DB");
202     sqlite3_close_v2(memorydb);
203     sqlite3_close_v2(filedb);
204     return nullptr;
205   }
206
207   sqlite3_backup_step(backup, -1);
208   sqlite3_backup_finish(backup);
209   sqlite3_close_v2(filedb);
210   return memorydb;
211 }
212
213 void DBHandleProvider::SetMemoryMode(pid_t pid) {
214   std::unique_lock<std::recursive_mutex> u(lock_);
215   if (is_memory_global_ && is_memory_)
216     return;
217
218   sqlite3* parser_db = GetMemoryDBHandle(parser_file_db_path_,
219       parser_memory_db_path_);
220   if (parser_db != nullptr)
221     parser_memory_db_handle_.reset(parser_db);
222
223   if (is_memory_ == is_memory_global_) {  /* first call */
224     sqlite3* global_parser_file_db = GetMemoryDBHandle(
225         global_parser_file_db_path_, global_parser_memory_db_path);
226     if (global_parser_file_db)
227       global_parser_memory_db_handle_.reset(global_parser_file_db);
228     sqlite3* cert_db = GetMemoryDBHandle(cert_file_db_path_,
229         cert_memory_db_path);
230     if (cert_db != nullptr)
231       cert_memory_db_handle_.reset(cert_db);
232
233     if (pid_list_.find(pid) == pid_list_.end())
234       pid_list_.insert(pid);
235   }
236
237   is_memory_ = true;
238   is_memory_global_ = true;
239   LOGD("Set Memory mode : Memory");
240 }
241
242 void DBHandleProvider::UnsetMemoryMode(pid_t pid) {
243   std::unique_lock<std::recursive_mutex> u(lock_);
244   if (!is_memory_global_ && !is_memory_)
245     return;
246
247   parser_memory_db_handle_.reset(nullptr);
248   cert_memory_db_handle_.reset(nullptr);
249   global_parser_memory_db_handle_.reset(nullptr);
250
251   auto it = pid_list_.find(pid);
252   if (it != pid_list_.end())
253     pid_list_.erase(it);
254   else
255     LOGE("Given pid is not exists in pid list : %d", pid);
256
257   is_memory_ = false;
258   is_memory_global_ = false;
259   LOGD("Set Memory mode : File");
260 }
261
262 bool DBHandleProvider::IsMemoryDBActive(pid_t pid, bool write) {
263   return (is_memory_ && pid_list_.find(pid) == pid_list_.end() && !write);
264 }
265
266 }  // namespace database
267 }  // namespace pkgmgr_server