Improve handling of cache
[platform/core/appfw/pkgmgr-info.git] / src / server / database / query_handler.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 "query_handler.hh"
18
19 #include <shared_mutex>
20 #include <tuple>
21 #include <vector>
22
23 #include "utils/logging.hh"
24 #include "cache_flag.hh"
25 #include "db_handle_provider.hh"
26
27 #include "pkgmgrinfo_debug.h"
28 #include "pkgmgrinfo_internal.h"
29 #include "pkgmgr_query_index.h"
30
31 namespace {
32
33 constexpr const char query_appinfo_get_localed_label[] =
34     "SELECT COALESCE((SELECT app_label FROM package_app_localized_info "
35     "WHERE app_id=? AND app_locale=?),"
36     "(SELECT app_label FROM package_app_localized_info WHERE "
37     "app_id=? AND app_locale='No Locale'))";
38
39 constexpr const char query_appinfo_get_datacontrol_info[] =
40     "SELECT app_id, access FROM "
41     "package_app_data_control WHERE "
42     "providerid=? AND type=?";
43
44 constexpr const char query_appinfo_get_datacontrol_appid[] =
45     "SELECT app_id FROM package_app_data_control "
46     "WHERE providerid=?";
47
48 constexpr const char query_appinfo_get_datacontrol_trusted_info[] =
49     "SELECT app_id, trusted FROM package_app_data_control "
50     "WHERE providerid=? AND type=?";
51
52 constexpr const char query_appinfo_get_datacontrol_privileges[] =
53     "SELECT privilege FROM package_app_data_control_privilege "
54     "WHERE providerid=? AND type=?";
55
56 constexpr const char query_appinfo_get_appcontrol_privileges[] =
57     "SELECT app_control, privilege FROM package_app_app_control_privilege "
58     "WHERE app_id=?";
59
60 constexpr const char query_plugininfo_get_appids[] =
61     "SELECT appid FROM "
62     "package_plugin_info WHERE pkgid=? AND "
63     "plugin_type=? AND plugin_name=?";
64
65 constexpr const char query_get_pkg_updateinfo_1[] =
66     "SELECT package, update_version, update_type "
67     "FROM package_update_info";
68 constexpr const char query_get_pkg_updateinfo_2[] =
69     "SELECT package, update_version, update_type "
70     "FROM package_update_info WHERE package=?";
71
72 constexpr const char query_pkginfo_set_usr_installed_storage_1[] =
73     "UPDATE package_info SET installed_storage=?, external_path=? "
74     "WHERE package=?";
75 constexpr const char query_pkginfo_set_usr_installed_storage_2[] =
76     "UPDATE package_app_info SET app_installed_storage=?, "
77     "app_external_path=? WHERE package=?";
78
79 constexpr const char query_certinfo_compare_pkg_certinfo[] =
80     "SELECT package, "
81     "COALESCE(author_signer_cert, -1) FROM package_cert_info WHERE "
82     "package IN (?, ?)";
83
84 constexpr const char query_certinfo_compare_app_certinfo[] =
85     "SELECT app_id, package FROM "
86     "package_app_info WHERE app_id IN (?, ?)";
87
88 constexpr const char query_pkginfo_delete_certinfo[] =
89     "UPDATE package_cert_info SET "
90     "package_count = package_count - 1 WHERE package=?";
91
92 // For pkgmgr_parser
93 constexpr const char query_insert_package_plugin_execution_info[] =
94     "INSERT INTO package_plugin_info "
95     "(pkgid, appid, plugin_type, plugin_name) "
96     "VALUES (?, ?, ?, ?)";
97
98 constexpr const char query_delete_package_plugin_execution_info[] =
99     "DELETE FROM package_plugin_info WHERE pkgid=?";
100
101 constexpr const char query_update_global_app_disable[] =
102     "INSERT OR REPLACE INTO package_app_info_for_uid ("
103     "  app_id, uid, is_disabled, is_splash_screen_enabled) "
104     "VALUES (?, ?, ?,"
105     "  (SELECT app_splash_screen_display FROM package_app_info"
106     "   WHERE app_id=?))";
107
108 constexpr const char query_update_app_disable_info[] =
109     "UPDATE package_app_info SET app_disable=? "
110     "WHERE app_id=?";
111
112 constexpr const char query_update_pkg_disable_info[] =
113     "UPDATE package_info SET package_disable=? "
114     "WHERE package=?";
115
116 constexpr const char query_update_global_app_splash_screen_display_info[] =
117     "INSERT OR REPLACE INTO package_app_info_for_uid("
118     "  app_id, uid, is_splash_screen_enabled) "
119     "VALUES (?, ?, ?)";
120
121 constexpr const char query_update_app_splash_screen_display_info[] =
122     "UPDATE package_app_info SET app_splash_screen_display=? "
123     "WHERE app_id=?";
124
125 constexpr const char query_update_app_label_info[] =
126     "UPDATE package_app_localized_info SET app_label=? "
127     "WHERE app_id=? AND app_label IS NOT NULL";
128
129 constexpr const char query_update_app_icon_info[] =
130     "UPDATE package_app_localized_info SET app_icon=? "
131     "WHERE app_id=? AND app_icon IS NOT NULL";
132
133 constexpr const char query_update_tep_info[] =
134     "UPDATE package_info SET package_tep_name=? "
135     "WHERE package=?";
136
137 constexpr const char query_register_pkg_update_info[] =
138     "UPDATE package_update_info "
139     "SET update_version=?, update_type=? "
140     "WHERE package=?";
141
142 constexpr const char query_unregister_pkg_update_info[] =
143     "UPDATE package_update_info "
144     "SET update_type='none' WHERE package=?";
145
146 constexpr const char query_unregister_all_pkg_update_info[] =
147     "UPDATE package_update_info "
148     "SET update_type='none'";
149
150 class QueryMaker {
151  public:
152   using CacheChangeFlag = pkgmgr_server::database::CacheChangeFlag;
153   std::vector<std::tuple<const char*, CacheChangeFlag, int>> query_raw_ = {
154     { query_appinfo_get_localed_label, CacheChangeFlag::NONE, 0 },
155     { query_appinfo_get_datacontrol_info, CacheChangeFlag::NONE, 0 },
156     { query_appinfo_get_datacontrol_appid, CacheChangeFlag::NONE, 0 },
157     { query_appinfo_get_datacontrol_trusted_info, CacheChangeFlag::NONE, 0 },
158     { query_appinfo_get_datacontrol_privileges, CacheChangeFlag::NONE, 0 },
159     { query_appinfo_get_appcontrol_privileges, CacheChangeFlag::NONE, 0 },
160     { query_plugininfo_get_appids, CacheChangeFlag::NONE, 0 },
161     { query_get_pkg_updateinfo_1, CacheChangeFlag::NONE, 0 },
162     { query_get_pkg_updateinfo_2, CacheChangeFlag::NONE, 0 },
163     { query_pkginfo_set_usr_installed_storage_1, CacheChangeFlag::PKG, 2 },
164     { query_pkginfo_set_usr_installed_storage_2, CacheChangeFlag::APPBYPKG, 2 },
165     { query_certinfo_compare_pkg_certinfo, CacheChangeFlag::NONE, 0 },
166     { query_certinfo_compare_app_certinfo, CacheChangeFlag::NONE, 0 },
167     { query_pkginfo_delete_certinfo, CacheChangeFlag::NONE, 0 },
168
169     { query_insert_package_plugin_execution_info, CacheChangeFlag::PKG, 0 },
170     { query_delete_package_plugin_execution_info, CacheChangeFlag::PKG, 0 },
171     { query_update_global_app_disable, CacheChangeFlag::APP, 0 },
172     { query_update_app_disable_info, CacheChangeFlag::APP, 1 },
173     { query_update_pkg_disable_info, CacheChangeFlag::PKG, 1 },
174     { query_update_global_app_splash_screen_display_info, CacheChangeFlag::APP, 0 },
175     { query_update_app_splash_screen_display_info, CacheChangeFlag::APP, 1 },
176     { query_update_app_label_info, CacheChangeFlag::APP, 1 },
177     { query_update_app_icon_info, CacheChangeFlag::APP, 1 },
178     { query_update_tep_info, CacheChangeFlag::PKG, 1 },
179     { query_register_pkg_update_info, CacheChangeFlag::NONE, 0 },
180     { query_unregister_pkg_update_info, CacheChangeFlag::NONE, 0 },
181     { query_unregister_all_pkg_update_info, CacheChangeFlag::NONE, 0 },
182   };
183
184   const std::tuple<const char*, CacheChangeFlag, int>& GetQueryInfo(int index) {
185     return query_raw_[index];
186   }
187 };
188
189 QueryMaker __query_maker;
190
191 void __free_argument(gpointer data) {
192   query_args* args = reinterpret_cast<query_args*>(data);
193   g_list_free(args->argument);
194   free(args);
195 }
196
197 void __free_query_list(GList* queries, GList* args_list) {
198   g_list_free(queries);
199   g_list_free_full(args_list, __free_argument);
200 }
201
202 }  // namespace
203
204 namespace pkgmgr_server {
205 namespace database {
206
207 QueryHandler::QueryHandler(uid_t uid, int pid)
208     : AbstractDBHandler(uid, pid), uid_(uid) {}
209
210 QueryHandler::~QueryHandler() {}
211
212 void QueryHandler::SetQueryArgs(
213     std::vector<pkgmgr_common::parcel::QueryArgs> query_args) {
214   query_args_ = std::move(query_args);
215 }
216
217 std::string QueryHandler::GetString() { return std::string(); }
218 int QueryHandler::GetInt() { return 0; }
219 int QueryHandler::GetRecordCount() { return 0; }
220
221 std::vector<pkgmgr_common::parcel::StrArgs> QueryHandler::GetResult() {
222   return std::move(result_);
223 }
224
225 int QueryHandler::ExecuteReadQuery(GList* queries, GList* args_list) {
226   std::shared_lock<std::shared_mutex> s(lock_);
227   if (!Connect()) {
228     LOG(ERROR) << "Failed to connect database";
229     return PMINFO_R_ERROR;
230   }
231
232   std::vector<std::pair<sqlite3*, uid_t>> conn_list = GetConnection();
233   int ret = PMINFO_R_ERROR;
234   for (auto& conn : conn_list) {
235     for (GList* it = args_list; it; it = it->next) {
236       GList* list = nullptr;
237       int row = 0;
238       int col = 0;
239
240       query_args* params = reinterpret_cast<query_args*>(it->data);
241       ret = get_query_result(conn.first, (const char *)queries->data,
242           params->argument, &list, &row, &col);
243       if (ret == PMINFO_R_ERROR) {
244         LOG(ERROR) << "Failed to execute query";
245         return ret;
246       }
247
248       GList* tmp = list;
249       for (int i = 0; i < row; ++i) {
250         pkgmgr_common::parcel::StrArgs vt;
251         for (int j = 0; j < col; ++j) {
252           if (!tmp->data)
253             vt.emplace_back(std::nullopt);
254           else
255             vt.emplace_back(reinterpret_cast<char *>(tmp->data));
256           tmp = tmp->next;
257         }
258         result_.emplace_back(std::move(vt));
259       }
260
261       g_list_free_full(list, free);
262     }
263   }
264
265   return ret;
266 }
267
268 int QueryHandler::ExecuteWriteQuery(GList* queries, GList* args_list,
269     const std::vector<std::pair<CacheChangeFlag, std::string>>& changes) {
270   std::unique_lock<std::shared_mutex> u(lock_);
271   if (!Connect()) {
272     LOG(ERROR) << "Failed to connect database";
273     return PMINFO_R_ERROR;
274   }
275
276   std::vector<std::pair<sqlite3*, uid_t>> conn_list = GetConnection();
277   int ret = PMINFO_R_ERROR;
278   bool is_writer = DBHandleProvider::IsWriter(GetPID());
279   for (auto& conn : conn_list) {
280     ret = execute_write_queries(conn.first, queries, args_list);
281     if (ret != PMINFO_R_OK) {
282       LOG(ERROR) << "Failed to execute";
283       break;
284     }
285   }
286
287   if (ret != PMINFO_R_OK || is_writer || changes.size() == 0 ||
288       CacheFlag::GetStatus() != CacheFlag::Status::PREPARED)
289     return ret;
290
291   bool success = true;
292   CacheFlag::SetStatus(CacheFlag::Status::PREPARING);
293   auto lock = CacheFlag::GetWriterLock();
294   for (auto& conn : conn_list) {
295     auto& provider = database::DBHandleProvider::GetInst(conn.second);
296     for (const auto& [flag, name] : changes) {
297       switch (flag) {
298       case CacheChangeFlag::PKG:
299         success = provider.UpdateCachePkg(conn.first, uid_, name, GetLocale());
300         break;
301       case CacheChangeFlag::APP:
302         success = provider.UpdateCacheApp(conn.first, uid_, name, GetLocale());
303         break;
304       case CacheChangeFlag::APPBYPKG:
305         success =
306             provider.UpdateCacheAppByPkgid(conn.first, uid_, name, GetLocale());
307         break;
308       default:
309         break;
310       }
311
312       if (!success) {
313         LOG(ERROR) << "Write query failed. " << static_cast<int>(flag) << ' '
314                    << name;
315         break;
316       }
317     }
318
319     if (!success) {
320       provider.TrimCache();
321       break;
322     }
323   }
324
325   CacheFlag::SetStatus(success ?
326       CacheFlag::Status::PREPARED : CacheFlag::Status::UNPREPARED);
327
328   return PMINFO_R_OK;
329 }
330
331 int QueryHandler::Execute() {
332   GList* queries = nullptr;
333   GList* args_list = nullptr;
334   std::vector<std::pair<CacheChangeFlag, std::string>> changes;
335   for (auto& [queryIndex, args] : query_args_) {
336     const auto& query_info = __query_maker.GetQueryInfo(queryIndex);
337     const char* query = std::get<0>(query_info);
338     if (query == nullptr) {
339       LOG(ERROR) << "Failed to get query";
340       __free_query_list(queries, args_list);
341       return PMINFO_R_ERROR;
342     }
343
344     queries = g_list_append(queries, (gpointer)query);
345     query_args* arg = reinterpret_cast<query_args*>(
346         calloc(1, sizeof(query_args)));
347     if (arg == nullptr) {
348       LOG(ERROR) << "Out of memory";
349       __free_query_list(queries, args_list);
350       return PMINFO_R_ERROR;
351     }
352     arg->len = args.size();
353     for (auto& argument : args) {
354       arg->argument = g_list_append(arg->argument,
355           gpointer(argument ? (*argument).c_str() : nullptr));
356     }
357
358     args_list = g_list_append(args_list, arg);
359
360     if (GetOpType() == pkgmgr_common::DBOperationType::OPERATION_TYPE_READ)
361       continue;
362
363     CacheChangeFlag flag = std::get<1>(query_info);
364     if (flag == CacheChangeFlag::NONE)
365       continue;
366
367     /* Cache changed query steps */
368     unsigned int idx = std::get<2>(query_info);
369     if (args.size() <= idx) {
370       LOG(ERROR) << "Invalid query argument";
371       __free_query_list(queries, args_list);
372       return PMINFO_R_ERROR;
373     }
374
375     if (!args[idx])
376       continue;
377
378     changes.emplace_back(std::make_pair(flag, *args[idx]));
379   }
380
381   if (GetOpType() == pkgmgr_common::DBOperationType::OPERATION_TYPE_READ) {
382     int ret = ExecuteReadQuery(queries, args_list);
383     __free_query_list(queries, args_list);
384     return ret;
385   } else {
386     int ret = ExecuteWriteQuery(queries, args_list, changes);
387     __free_query_list(queries, args_list);
388     return ret;
389   }
390 }
391
392 }  // namespace database
393 }  // namespace pkgmgr_server