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