2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <pkgmgr-info.h>
22 #include <tzplatform_config.h>
29 #include "notification-ex/common.h"
30 #include "notification-ex/db_manager.h"
31 #include "notification-ex/item_inflator.h"
32 #include "notification-ex/iitem_info_internal.h"
33 #include "notification-ex/ex_util.h"
38 #define LOG_TAG "NOTIFICATION_EX"
40 #define CREATE_NOTIFICATION_TABLE \
41 "PRAGMA journal_mode = PERSIST;\n" \
42 "PRAGMA synchronous = FULL;\n" \
43 "PRAGMA foreign_keys = ON;\n" \
44 "CREATE TABLE IF NOT EXISTS noti_ex_list (\n" \
45 " root_id TEXT NOT NULL,\n" \
46 " app_id TEXT NOT NULL,\n" \
49 " priv_id INTEGER PRIMARY KEY,\n" \
51 " policy INTEGER,\n" \
52 " data TEXT NOT NULL,\n" \
53 " insert_time INTEGER,\n" \
54 " hide_list TEXT,\n" \
55 " UNIQUE (root_id, app_id, uid));\n" \
56 "CREATE TABLE IF NOT EXISTS receiver_list (\n" \
57 " root_id TEXT NOT NULL,\n" \
58 " app_id TEXT NOT NULL,\n" \
60 " receiver_group TEXT NOT NULL,\n" \
61 " FOREIGN KEY (root_id, app_id, uid)\n" \
62 " REFERENCES noti_ex_list(root_id, app_id, uid) ON DELETE CASCADE);\n"
64 #define DBPATH tzplatform_mkpath(TZ_SYS_DB, ".notification.db")
65 #define NOTI_LIMIT 100
68 using namespace tizen_base;
69 using namespace notification::item;
71 namespace notification {
73 DBManager::DBManager() = default;
74 DBManager::~DBManager() = default;
76 sqlite3* DBManager::OpenDB() {
80 ret = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READWRITE, nullptr);
81 if (ret != SQLITE_OK) {
82 LOGE("open db(%s) error: %d", DBPATH, ret);
89 void DBManager::CloseDB(sqlite3* db) {
93 ret = sqlite3_close_v2(db);
96 LOGE("close db error");
99 int DBManager::ExecuteQuery(sqlite3* db, const char* query, int* num_changes) {
100 int ret = ERROR_NONE;
103 if (db == nullptr || query == nullptr)
104 return ERROR_INVALID_PARAMETER;
106 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
107 if (ret != SQLITE_OK) {
108 /* LCOV_EXCL_START */
109 LOGE("Sqlite3 err[%d][%s]", ret, sqlite3_errmsg(db));
110 return ERROR_FROM_DB;
114 ret = sqlite3_step(stmt);
115 if (ret == SQLITE_OK || ret == SQLITE_DONE) {
116 if (num_changes != nullptr)
117 *num_changes = sqlite3_changes(db);
120 /* LCOV_EXCL_START */
121 LOGE("Sqlite err[%d][%s]", ret, sqlite3_errmsg(db));
126 sqlite3_finalize(stmt);
130 int DBManager::ExecuteQuery(const char* query, int* num_changes) {
133 if (query == nullptr)
134 return ERROR_INVALID_PARAMETER;
136 sqlite3* db = OpenDB();
138 return ERROR_FROM_DB;
140 ret = ExecuteQuery(db, query, num_changes);
146 int DBManager::GetSequence(sqlite3* db, int64_t* seq) {
147 int ret = ERROR_NONE;
150 if (db == nullptr || seq == nullptr)
151 return ERROR_INVALID_PARAMETER;
153 string query = "SELECT IFNULL(MIN(priv_id), 0), IFNULL(MAX(priv_id), 0)"
154 " FROM noti_ex_list";
155 ret = sqlite3_prepare_v2(db, query.c_str(), query.size(), &stmt, nullptr);
156 if (ret != SQLITE_OK) {
157 /* LCOV_EXCL_START */
158 LOGE("Sqlite3 err[%d][%s]", ret, sqlite3_errmsg(db));
159 return ERROR_FROM_DB;
163 ret = sqlite3_step(stmt);
164 if (ret == SQLITE_ROW) {
165 int64_t min_p = sqlite3_column_int64(stmt, 0);
169 *seq = sqlite3_column_int64(stmt, 1) + 1;
172 /* LCOV_EXCL_START */
173 LOGE("Sqlite err [%d][%s]", ret, sqlite3_errmsg(db));
178 sqlite3_finalize(stmt);
182 int DBManager::CheckDBIntegrity(void* user_data, int argc,
183 char** argv, char** notUsed) {
184 bool* is_db_corrupted = static_cast<bool*>(user_data);
186 if (std::string(argv[0]).compare("ok")) {
187 LOGE("db integrity result : %s", argv[0]);
188 *is_db_corrupted = true;
192 LOGI("db integrity result : %s", argv[0]);
196 int DBManager::RecoverCorruptedDB(sqlite3* db) {
197 int ret = ERROR_NONE;
198 char* errmsg = nullptr;
200 LOGI("DB is corrupted, start to recover corrupted db");
205 ret = sqlite3_open_v2(DBPATH, &db,
206 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
207 if (ret != SQLITE_OK) {
208 LOGE("Failed to open db[%d]", ret);
214 ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, nullptr, nullptr, &errmsg);
215 if (ret != SQLITE_OK) {
216 LOGE("Failed to exec query[%d][%s]", ret, errmsg);
222 sqlite3_free(errmsg);
227 int DBManager::InitializeDB() {
228 int ret = ERROR_NONE;
231 char *errmsg = nullptr;
232 bool is_db_corrupted = false;
234 sql_ret = sqlite3_open_v2(DBPATH, &db,
235 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
236 if (sql_ret != SQLITE_OK) {
237 LOGE("Failed to open db[%d]", ret);
242 sql_ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, nullptr, nullptr, &errmsg);
243 if (sql_ret != SQLITE_OK) {
244 LOGE("Failed to exec sqlite[%d][%s]", ret, errmsg);
249 sql_ret = sqlite3_exec(db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
250 if (sql_ret != SQLITE_OK) {
251 LOGE("Failed to exec sqlite[%d][%s]", ret, errmsg);
256 sql_ret = sqlite3_exec(db, "PRAGMA integrity_check",
257 CheckDBIntegrity, &is_db_corrupted, &errmsg);
258 if (sql_ret != SQLITE_OK || is_db_corrupted) {
259 LOGE("Failed to exec query[%d][%s]", sql_ret, errmsg);
264 if (sql_ret == SQLITE_CORRUPT || sql_ret == SQLITE_NOTADB || is_db_corrupted)
265 ret = RecoverCorruptedDB(db);
267 sqlite3_free(errmsg);
274 void DBManager::InitializeData() {
277 query = sqlite3_mprintf("DELETE FROM noti_ex_list WHERE policy & %d",
278 static_cast<int>(item::AbstractItem::Policy::OnBootClear));
280 LOGE("OOM - sql query");
284 ExecuteQuery(query, nullptr);
288 void DBManager::CheckLimit(shared_ptr<item::AbstractItem> addedItem, sqlite3* db) {
291 sqlite3_stmt* stmt = nullptr;
292 sqlite3_stmt* delete_stmt = nullptr;
294 static_pointer_cast<IItemInfoInternal>(addedItem->GetInfo())->GetUid();
296 ret = GetCount(addedItem->GetSenderAppId(), uid, &count);
297 if (ret != ERROR_NONE || count <= NOTI_LIMIT)
300 query = sqlite3_mprintf("SELECT root_id FROM noti_ex_list WHERE uid = %d"
301 " AND app_id = %Q ORDER BY insert_time ASC",
302 uid, addedItem->GetSenderAppId().c_str());
303 if (query == nullptr) {
304 LOGE("OOM - sql query");
308 ret = sqlite3_prepare_v2(db, query, -1, &stmt, nullptr);
309 if (ret != SQLITE_OK) {
310 /* LCOV_EXCL_START */
311 LOGE("sqlite3_prepare_v2 Failed [%d][%s]", ret, sqlite3_errmsg(db));
319 query = sqlite3_mprintf("DELETE FROM noti_ex_list"
320 " WHERE root_id = ? AND app_id = %Q AND uid = %d",
321 addedItem->GetSenderAppId().c_str(), uid);
322 if (query == nullptr) {
323 LOGE("OOM - sql query");
324 sqlite3_finalize(stmt);
328 ret = sqlite3_prepare_v2(db, query, -1, &delete_stmt, nullptr);
329 if (ret != SQLITE_OK) {
330 /* LCOV_EXCL_START */
331 LOGE("sqlite3_prepare_v2 Failed [%d][%s]", ret, sqlite3_errmsg(db));
336 while (sqlite3_step(stmt) == SQLITE_ROW && count > 0) {
337 ret = sqlite3_bind_text(delete_stmt, 1,
338 reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)),
339 -1, SQLITE_TRANSIENT);
340 if (ret != SQLITE_OK) {
341 LOGE("sqlite3_bind_int() error: %d(%s)", ret, sqlite3_errmsg(db));
345 ret = sqlite3_step(delete_stmt);
346 if (ret != SQLITE_DONE) {
347 LOGE("step error: %d(%s)", ret, sqlite3_errmsg(db));
351 ret = sqlite3_reset(delete_stmt);
352 if (ret != SQLITE_OK) {
353 LOGE("sqlite3_reset() error: %d", ret);
357 sqlite3_clear_bindings(delete_stmt);
364 sqlite3_finalize(stmt);
366 sqlite3_finalize(delete_stmt);
371 int DBManager::UpdateReceiverList
372 (shared_ptr<item::AbstractItem> updatedItem, sqlite3* db) {
376 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid();
378 query = sqlite3_mprintf("DELETE FROM receiver_list"
379 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
380 updatedItem->GetId().c_str(), updatedItem->GetSenderAppId().c_str(),
383 LOGE("OOM - sql query");
384 return ERROR_OUT_OF_MEMORY;
387 ret = ExecuteQuery(db, query, nullptr);
390 if (ret != ERROR_NONE)
393 for (auto& i : updatedItem->GetReceiverList()) {
394 query = sqlite3_mprintf("INSERT INTO receiver_list"
395 " (root_id, app_id, uid, receiver_group)"
396 " VALUES (%Q, %Q, %d, %Q)",
397 updatedItem->GetId().c_str(),
398 updatedItem->GetSenderAppId().c_str(),
403 LOGE("OOM - sql query");
404 return ERROR_OUT_OF_MEMORY;
407 ret = ExecuteQuery(db, query, nullptr);
410 if (ret != ERROR_NONE)
416 int DBManager::InsertNotification(list<shared_ptr<item::AbstractItem>> addedItem) {
417 int ret = ERROR_NONE;
421 sqlite3* db = OpenDB();
424 return ERROR_FROM_DB;
426 if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
427 LOGE("begin transaction error : %s", sqlite3_errmsg(db));
429 return ERROR_FROM_DB;
432 for (auto& i : addedItem) {
433 uid_t uid = static_pointer_cast<IItemInfoInternal>(i->GetInfo())->GetUid();
434 ret = GetCount(0, i->GetId(), i->GetSenderAppId(), uid, &count);
435 if (ret != ERROR_NONE)
439 LOGE("already exist id :[%s] appid[%s]",
440 i->GetId().c_str(), i->GetSenderAppId().c_str());
441 ret = ERROR_ALREADY_EXIST_ID;
445 ret = GetSequence(db, &seq);
446 if (ret != ERROR_NONE)
449 static_pointer_cast<IItemInfoInternal>(i->GetInfo())->SetPrivateId(seq);
450 Bundle b = i->Serialize();
451 query = sqlite3_mprintf("INSERT INTO noti_ex_list"
452 " (root_id, app_id, uid, channel, priv_id, pkg_id, policy, data, insert_time)"
453 " VALUES (%Q, %Q, %d, %Q, %" PRId64 ", %Q, %d, %Q, %d)",
455 i->GetSenderAppId().c_str(),
457 i->GetChannel().c_str(),
458 static_pointer_cast<IItemInfoInternal>(i->GetInfo())->GetPrivateId(),
459 GetPkgId(i->GetSenderAppId(), uid).c_str(),
460 static_cast<int>(i->GetPolicy()),
461 reinterpret_cast<char*>(b.ToRaw().first.get()),
462 static_pointer_cast<IItemInfo>(i->GetInfo())->GetTime());
465 LOGE("OOM - sql query");
466 ret = ERROR_OUT_OF_MEMORY;
470 ret = ExecuteQuery(db, query, nullptr);
472 if (ret != ERROR_NONE)
475 ret = UpdateReceiverList(i, db);
476 if (ret != ERROR_NONE)
480 if (ret == ERROR_NONE) {
481 CheckLimit(*(addedItem.begin()), db);
482 if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
483 LOGE("end transaction error : %s", sqlite3_errmsg(db));
487 if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
488 LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
495 map<string, string> DBManager::GetHideMap() {
496 map<string, string> hide_map;
503 query = sqlite3_mprintf("SELECT root_id, app_id, uid, hide_list FROM noti_ex_list"
504 " WHERE hide_list IS NOT NULL");
506 LOGE("OOM - sql query");
516 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
517 if (ret != SQLITE_OK) {
518 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
525 while (sqlite3_step(stmt) == SQLITE_ROW) {
526 key = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) \
527 + string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) \
528 + string(to_string(sqlite3_column_int(stmt, 2)));
529 hide_map[key] = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
532 sqlite3_finalize(stmt);
537 int DBManager::GetCount(const string& app_id, uid_t uid, int* count) {
538 return GetCount(0, string(), app_id, uid, count);
541 int DBManager::GetCount(int64_t priv_id, const string& root_id, const string& app_id,
542 uid_t uid, int* count) {
549 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
550 " WHERE priv_id = %" PRId64 "", priv_id);
551 } else if (root_id.empty()) {
552 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
553 " WHERE app_id = %Q AND uid = %d", app_id.c_str(), uid);
555 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
556 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
557 root_id.c_str(), app_id.c_str(), uid);
560 LOGE("OOM - sql query");
561 return ERROR_OUT_OF_MEMORY;
567 return ERROR_FROM_DB;
570 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
571 if (ret != SQLITE_OK) {
572 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
575 return ERROR_FROM_DB;
579 ret = sqlite3_step(stmt);
580 if (ret == SQLITE_ROW)
581 *count = sqlite3_column_int(stmt, 0);
585 sqlite3_finalize(stmt);
590 int DBManager::UpdateHideList(shared_ptr<item::AbstractItem> updatedItem,
591 const string& hide_list) {
595 query = sqlite3_mprintf("UPDATE noti_ex_list SET hide_list = %Q"
596 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
597 hide_list.c_str(), updatedItem->GetId().c_str(),
598 updatedItem->GetSenderAppId().c_str(),
599 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid());
601 LOGE("OOM - sql query");
602 return ERROR_OUT_OF_MEMORY;
605 ret = ExecuteQuery(query, nullptr);
611 int DBManager::UpdateNotification(shared_ptr<item::AbstractItem> updatedItem) {
615 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid();
616 int64_t priv_id = static_pointer_cast<IItemInfoInternal>(
617 updatedItem->GetInfo())->GetPrivateId();
619 ret = GetCount(priv_id,
620 updatedItem->GetId(), updatedItem->GetSenderAppId(), uid, &count);
621 if (ret != ERROR_NONE) {
622 LOGE("fail to get count");
627 LOGE("not exist priv_id(%" PRId64 ") id(%s) for appid(%s)", priv_id,
628 updatedItem->GetId().c_str(), updatedItem->GetSenderAppId().c_str());
629 return ERROR_NOT_EXIST_ID;
632 sqlite3* db = OpenDB();
634 return ERROR_FROM_DB;
636 Bundle b = updatedItem->Serialize();
637 query = sqlite3_mprintf("UPDATE noti_ex_list SET"
638 " pkg_id = %Q, channel = %Q, policy = %d, data = %Q, insert_time = %d"
639 " WHERE priv_id = %" PRId64 "",
640 GetPkgId(updatedItem->GetSenderAppId(), uid).c_str(),
641 updatedItem->GetChannel().c_str(),
642 static_cast<int>(updatedItem->GetPolicy()),
643 reinterpret_cast<char*>(b.ToRaw().first.get()),
644 static_pointer_cast<IItemInfo>(updatedItem->GetInfo())->GetTime(),
648 LOGE("OOM - sql query");
650 return ERROR_OUT_OF_MEMORY;
653 if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
654 LOGE("begin transaction error : %s", sqlite3_errmsg(db));
657 return ERROR_FROM_DB;
660 ret = ExecuteQuery(db, query, nullptr);
662 if (ret != ERROR_NONE)
665 ret = UpdateReceiverList(updatedItem, db);
668 if (ret == ERROR_NONE) {
669 if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
670 LOGE("end transaction error : %s", sqlite3_errmsg(db));
674 if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
675 LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
682 list<shared_ptr<item::AbstractItem>> DBManager::ExecuteGetList(char* query) {
686 list<shared_ptr<item::AbstractItem>> item_list;
689 LOGE("Invalid parameter");
697 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
698 if (ret != SQLITE_OK) {
699 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
704 while (sqlite3_step(stmt) == SQLITE_ROW) {
705 LOGE("[%s]", sqlite3_column_text(stmt, 0));
707 Bundle serialized(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
708 shared_ptr<item::AbstractItem> gen_item = item::ItemInflator::Create(serialized);
709 item_list.emplace_back(gen_item);
712 sqlite3_finalize(stmt);
717 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(
718 string app_id, uid_t uid, string channel) {
720 list<shared_ptr<item::AbstractItem>> item_list;
722 if (!channel.empty()) {
723 query = sqlite3_mprintf("SELECT data FROM noti_ex_list WHERE uid = %d "
724 "AND app_id = %Q AND channel = %Q ORDER BY insert_time DESC", uid,
725 app_id.c_str(), channel.c_str());
727 query = sqlite3_mprintf("SELECT data FROM noti_ex_list WHERE uid = %d "
728 "AND app_id = %Q ORDER BY insert_time DESC", uid, app_id.c_str());
732 LOGE("OOM - sql query");
736 item_list = ExecuteGetList(query);
742 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList
743 (string app_id, string root_id, uid_t uid) {
745 list<shared_ptr<item::AbstractItem>> item_list;
747 query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
748 " WHERE uid = %d AND app_id = %Q AND root_id = %Q",
749 uid, app_id.c_str(), root_id.c_str());
752 LOGE("OOM - sql query");
756 item_list = ExecuteGetList(query);
762 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList
763 (string app_id, int64_t priv_id, uid_t uid) {
765 list<shared_ptr<item::AbstractItem>> item_list;
767 query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
768 " WHERE uid = %d AND app_id = %Q AND priv_id = %" PRId64 "",
769 uid, app_id.c_str(), priv_id);
772 LOGE("OOM - sql query");
776 item_list = ExecuteGetList(query);
782 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(
783 uid_t uid, string channel) {
786 list<shared_ptr<item::AbstractItem>> item_list;
788 /* Check current sim status */
789 ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &sim_mode);
791 sim_mode = VCONFKEY_TELEPHONY_SIM_INSERTED;
792 LOGI("vconf_get_int");
795 string channel_query;
796 if (!channel.empty())
797 channel_query = " AND channel = '" + channel + "' ";
799 string simmode_query;
800 if (sim_mode != VCONFKEY_TELEPHONY_SIM_INSERTED) {
801 simmode_query = " AND (policy & " +
802 to_string(static_cast<int>(item::AbstractItem::Policy::SimMode)) +
806 string query_str = "SELECT data FROM noti_ex_list WHERE uid = %d " +
810 query = sqlite3_mprintf(query_str.c_str(), uid);
812 LOGE("OOM - sql query");
816 item_list = ExecuteGetList(query);
822 int DBManager::DeleteNotification(shared_ptr<item::AbstractItem> deletedItem) {
825 int64_t priv_id = static_pointer_cast<IItemInfoInternal>(
826 deletedItem->GetInfo())->GetPrivateId();
828 query = sqlite3_mprintf("DELETE FROM noti_ex_list WHERE priv_id = %" PRId64 "",
831 LOGE("OOM - sql query");
832 return ERROR_OUT_OF_MEMORY;
835 ret = ExecuteQuery(query, nullptr);
840 string DBManager::GetPkgId(const string& app_id, uid_t uid) {
841 pkgmgrinfo_pkginfo_h handle;
845 if (pkgmgrinfo_appinfo_get_usr_appinfo(app_id.c_str(), uid, &handle) == PMINFO_R_OK) {
846 if (pkgmgrinfo_appinfo_get_pkgid(handle, &buf) == PMINFO_R_OK) {
850 pkgmgrinfo_appinfo_destroy_appinfo(handle);
854 } // namespace notification