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;
420 sqlite3* db = OpenDB();
423 return ERROR_FROM_DB;
425 if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
426 LOGE("begin transaction error : %s", sqlite3_errmsg(db));
428 return ERROR_FROM_DB;
431 for (auto& i : addedItem) {
432 uid_t uid = static_pointer_cast<IItemInfoInternal>(i->GetInfo())->GetUid();
433 list<shared_ptr<item::AbstractItem>> item_list =
434 GetNotificationList(i->GetSenderAppId(), i->GetId(), uid);
436 if (!item_list.empty())
438 static_pointer_cast<IItemInfoInternal>(item_list.front()->GetInfo())->GetPrivateId();
440 ret = GetSequence(db, &priv_id);
442 if (ret != ERROR_NONE || priv_id == 0) {
443 LOGE("Failed to get pirv_id");
447 static_pointer_cast<IItemInfoInternal>(i->GetInfo())->SetPrivateId(priv_id);
448 Bundle b = i->Serialize();
450 query = sqlite3_mprintf("INSERT OR REPLACE INTO noti_ex_list"
451 " (root_id, app_id, uid, channel, priv_id, pkg_id, policy, data, insert_time)"
452 " VALUES (%Q, %Q, %d, %Q, %" PRId64 ", %Q, %d, %Q, %d)",
454 i->GetSenderAppId().c_str(),
456 i->GetChannel().c_str(),
458 GetPkgId(i->GetSenderAppId(), uid).c_str(),
459 static_cast<int>(i->GetPolicy()),
460 reinterpret_cast<char*>(b.ToRaw().first.get()),
461 static_pointer_cast<IItemInfo>(i->GetInfo())->GetTime());
463 LOGE("OOM - sql query");
464 ret = ERROR_OUT_OF_MEMORY;
468 ret = ExecuteQuery(db, query, nullptr);
470 if (ret != ERROR_NONE)
473 ret = UpdateReceiverList(i, db);
474 if (ret != ERROR_NONE)
478 if (ret == ERROR_NONE) {
479 CheckLimit(*(addedItem.begin()), db);
480 if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
481 LOGE("end transaction error : %s", sqlite3_errmsg(db));
485 if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
486 LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
493 map<string, string> DBManager::GetHideMap() {
494 map<string, string> hide_map;
501 query = sqlite3_mprintf("SELECT root_id, app_id, uid, hide_list FROM noti_ex_list"
502 " WHERE hide_list IS NOT NULL");
504 LOGE("OOM - sql query");
514 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
515 if (ret != SQLITE_OK) {
516 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
523 while (sqlite3_step(stmt) == SQLITE_ROW) {
524 key = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) \
525 + string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) \
526 + string(to_string(sqlite3_column_int(stmt, 2)));
527 hide_map[key] = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
530 sqlite3_finalize(stmt);
535 int DBManager::GetCount(const string& app_id, uid_t uid, int* count) {
536 return GetCount(0, string(), app_id, uid, count);
539 int DBManager::GetCount(int64_t priv_id, const string& root_id, const string& app_id,
540 uid_t uid, int* count) {
547 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
548 " WHERE priv_id = %" PRId64 "", priv_id);
549 } else if (root_id.empty()) {
550 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
551 " WHERE app_id = %Q AND uid = %d", app_id.c_str(), uid);
553 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
554 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
555 root_id.c_str(), app_id.c_str(), uid);
558 LOGE("OOM - sql query");
559 return ERROR_OUT_OF_MEMORY;
565 return ERROR_FROM_DB;
568 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
569 if (ret != SQLITE_OK) {
570 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
573 return ERROR_FROM_DB;
577 ret = sqlite3_step(stmt);
578 if (ret == SQLITE_ROW)
579 *count = sqlite3_column_int(stmt, 0);
583 sqlite3_finalize(stmt);
588 int DBManager::UpdateHideList(shared_ptr<item::AbstractItem> updatedItem,
589 const string& hide_list) {
593 query = sqlite3_mprintf("UPDATE noti_ex_list SET hide_list = %Q"
594 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
595 hide_list.c_str(), updatedItem->GetId().c_str(),
596 updatedItem->GetSenderAppId().c_str(),
597 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid());
599 LOGE("OOM - sql query");
600 return ERROR_OUT_OF_MEMORY;
603 ret = ExecuteQuery(query, nullptr);
609 int DBManager::UpdateNotification(shared_ptr<item::AbstractItem> updatedItem) {
613 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid();
614 int64_t priv_id = static_pointer_cast<IItemInfoInternal>(
615 updatedItem->GetInfo())->GetPrivateId();
617 ret = GetCount(priv_id,
618 updatedItem->GetId(), updatedItem->GetSenderAppId(), uid, &count);
619 if (ret != ERROR_NONE) {
620 LOGE("fail to get count");
625 LOGE("not exist priv_id(%" PRId64 ") id(%s) for appid(%s)", priv_id,
626 updatedItem->GetId().c_str(), updatedItem->GetSenderAppId().c_str());
627 return ERROR_NOT_EXIST_ID;
630 sqlite3* db = OpenDB();
632 return ERROR_FROM_DB;
634 Bundle b = updatedItem->Serialize();
635 query = sqlite3_mprintf("UPDATE noti_ex_list SET"
636 " pkg_id = %Q, channel = %Q, policy = %d, data = %Q, insert_time = %d"
637 " WHERE priv_id = %" PRId64 "",
638 GetPkgId(updatedItem->GetSenderAppId(), uid).c_str(),
639 updatedItem->GetChannel().c_str(),
640 static_cast<int>(updatedItem->GetPolicy()),
641 reinterpret_cast<char*>(b.ToRaw().first.get()),
642 static_pointer_cast<IItemInfo>(updatedItem->GetInfo())->GetTime(),
646 LOGE("OOM - sql query");
648 return ERROR_OUT_OF_MEMORY;
651 if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
652 LOGE("begin transaction error : %s", sqlite3_errmsg(db));
655 return ERROR_FROM_DB;
658 ret = ExecuteQuery(db, query, nullptr);
660 if (ret != ERROR_NONE)
663 ret = UpdateReceiverList(updatedItem, db);
666 if (ret == ERROR_NONE) {
667 if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
668 LOGE("end transaction error : %s", sqlite3_errmsg(db));
672 if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
673 LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
680 list<shared_ptr<item::AbstractItem>> DBManager::ExecuteGetList(char* query) {
684 list<shared_ptr<item::AbstractItem>> item_list;
687 LOGE("Invalid parameter");
695 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
696 if (ret != SQLITE_OK) {
697 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
702 while (sqlite3_step(stmt) == SQLITE_ROW) {
703 LOGE("[%s]", sqlite3_column_text(stmt, 0));
705 Bundle serialized(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
706 shared_ptr<item::AbstractItem> gen_item = item::ItemInflator::Create(serialized);
707 item_list.emplace_back(gen_item);
710 sqlite3_finalize(stmt);
715 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(
716 string app_id, uid_t uid, string channel) {
718 list<shared_ptr<item::AbstractItem>> item_list;
720 if (!channel.empty()) {
721 query = sqlite3_mprintf("SELECT data FROM noti_ex_list WHERE uid = %d "
722 "AND app_id = %Q AND channel = %Q ORDER BY insert_time DESC", uid,
723 app_id.c_str(), channel.c_str());
725 query = sqlite3_mprintf("SELECT data FROM noti_ex_list WHERE uid = %d "
726 "AND app_id = %Q ORDER BY insert_time DESC", uid, app_id.c_str());
730 LOGE("OOM - sql query");
734 item_list = ExecuteGetList(query);
740 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList
741 (string app_id, string root_id, uid_t uid) {
743 list<shared_ptr<item::AbstractItem>> item_list;
745 query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
746 " WHERE uid = %d AND app_id = %Q AND root_id = %Q",
747 uid, app_id.c_str(), root_id.c_str());
750 LOGE("OOM - sql query");
754 item_list = ExecuteGetList(query);
760 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList
761 (string app_id, int64_t priv_id, uid_t uid) {
763 list<shared_ptr<item::AbstractItem>> item_list;
765 query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
766 " WHERE uid = %d AND app_id = %Q AND priv_id = %" PRId64 "",
767 uid, app_id.c_str(), priv_id);
770 LOGE("OOM - sql query");
774 item_list = ExecuteGetList(query);
780 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(
781 uid_t uid, string channel) {
784 list<shared_ptr<item::AbstractItem>> item_list;
786 /* Check current sim status */
787 ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &sim_mode);
789 sim_mode = VCONFKEY_TELEPHONY_SIM_INSERTED;
790 LOGI("vconf_get_int");
793 string channel_query;
794 if (!channel.empty())
795 channel_query = " AND channel = '" + channel + "' ";
797 string simmode_query;
798 if (sim_mode != VCONFKEY_TELEPHONY_SIM_INSERTED) {
799 simmode_query = " AND (policy & " +
800 to_string(static_cast<int>(item::AbstractItem::Policy::SimMode)) +
804 string query_str = "SELECT data FROM noti_ex_list WHERE uid = %d " +
808 query = sqlite3_mprintf(query_str.c_str(), uid);
810 LOGE("OOM - sql query");
814 item_list = ExecuteGetList(query);
820 int DBManager::DeleteNotification(shared_ptr<item::AbstractItem> deletedItem) {
823 int64_t priv_id = static_pointer_cast<IItemInfoInternal>(
824 deletedItem->GetInfo())->GetPrivateId();
826 query = sqlite3_mprintf("DELETE FROM noti_ex_list WHERE priv_id = %" PRId64 "",
829 LOGE("OOM - sql query");
830 return ERROR_OUT_OF_MEMORY;
833 ret = ExecuteQuery(query, nullptr);
838 string DBManager::GetPkgId(const string& app_id, uid_t uid) {
839 pkgmgrinfo_pkginfo_h handle;
843 if (pkgmgrinfo_appinfo_get_usr_appinfo(app_id.c_str(), uid, &handle) == PMINFO_R_OK) {
844 if (pkgmgrinfo_appinfo_get_pkgid(handle, &buf) == PMINFO_R_OK) {
848 pkgmgrinfo_appinfo_destroy_appinfo(handle);
852 } // namespace notification