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 sqlite3_prepare_v2(db, query.c_str(), query.size(), &stmt, nullptr);
156 ret = sqlite3_step(stmt);
157 if (ret == SQLITE_ROW) {
158 int64_t min_p = sqlite3_column_int64(stmt, 0);
162 *seq = sqlite3_column_int64(stmt, 1) + 1;
165 /* LCOV_EXCL_START */
166 LOGE("Sqlite err [%d][%s]", ret, sqlite3_errmsg(db));
171 sqlite3_finalize(stmt);
175 int DBManager::CheckDBIntegrity(void* user_data, int argc,
176 char** argv, char** notUsed) {
177 bool* is_db_corrupted = static_cast<bool*>(user_data);
179 if (std::string(argv[0]).compare("ok")) {
180 LOGE("db integrity result : %s", argv[0]);
181 *is_db_corrupted = true;
185 LOGI("db integrity result : %s", argv[0]);
189 int DBManager::RecoverCorruptedDB(sqlite3* db) {
190 int ret = ERROR_NONE;
191 char* errmsg = nullptr;
193 LOGI("DB is corrupted, start to recover corrupted db");
198 ret = sqlite3_open_v2(DBPATH, &db,
199 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
200 if (ret != SQLITE_OK) {
201 LOGE("Failed to open db[%d]", ret);
207 ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, nullptr, nullptr, &errmsg);
208 if (ret != SQLITE_OK) {
209 LOGE("Failed to exec query[%d][%s]", ret, errmsg);
215 sqlite3_free(errmsg);
220 int DBManager::InitializeDB() {
221 int ret = ERROR_NONE;
224 char *errmsg = nullptr;
225 bool is_db_corrupted = false;
227 sql_ret = sqlite3_open_v2(DBPATH, &db,
228 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
229 if (sql_ret != SQLITE_OK) {
230 LOGE("Failed to open db[%d]", ret);
235 sql_ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, nullptr, nullptr, &errmsg);
236 if (sql_ret != SQLITE_OK) {
237 LOGE("Failed to exec sqlite[%d][%s]", ret, errmsg);
242 sql_ret = sqlite3_exec(db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
243 if (sql_ret != SQLITE_OK) {
244 LOGE("Failed to exec sqlite[%d][%s]", ret, errmsg);
249 sql_ret = sqlite3_exec(db, "PRAGMA integrity_check",
250 CheckDBIntegrity, &is_db_corrupted, &errmsg);
251 if (sql_ret != SQLITE_OK || is_db_corrupted) {
252 LOGE("Failed to exec query[%d][%s]", sql_ret, errmsg);
257 if (sql_ret == SQLITE_CORRUPT || sql_ret == SQLITE_NOTADB || is_db_corrupted)
258 ret = RecoverCorruptedDB(db);
260 sqlite3_free(errmsg);
267 void DBManager::InitializeData() {
270 query = sqlite3_mprintf("DELETE FROM noti_ex_list WHERE policy & %d",
271 static_cast<int>(item::AbstractItem::Policy::OnBootClear));
273 LOGE("OOM - sql query");
277 ExecuteQuery(query, nullptr);
281 void DBManager::CheckLimit(shared_ptr<item::AbstractItem> addedItem, sqlite3* db) {
284 sqlite3_stmt* stmt = nullptr;
285 sqlite3_stmt* delete_stmt = nullptr;
287 static_pointer_cast<IItemInfoInternal>(addedItem->GetInfo())->GetUid();
289 ret = GetCount(addedItem->GetSenderAppId(), uid, &count);
290 if (ret != ERROR_NONE || count <= NOTI_LIMIT)
293 query = sqlite3_mprintf("SELECT root_id FROM noti_ex_list WHERE uid = %d"
294 " AND app_id = %Q ORDER BY insert_time ASC",
295 uid, addedItem->GetSenderAppId().c_str());
296 if (query == nullptr) {
297 LOGE("OOM - sql query");
301 ret = sqlite3_prepare_v2(db, query, -1, &stmt, nullptr);
302 if (ret != SQLITE_OK) {
303 /* LCOV_EXCL_START */
304 LOGE("sqlite3_prepare_v2 Failed [%d][%s]", ret, sqlite3_errmsg(db));
312 query = sqlite3_mprintf("DELETE FROM noti_ex_list"
313 " WHERE root_id = ? AND app_id = %Q AND uid = %d",
314 addedItem->GetSenderAppId().c_str(), uid);
315 if (query == nullptr) {
316 LOGE("OOM - sql query");
317 sqlite3_finalize(stmt);
321 ret = sqlite3_prepare_v2(db, query, -1, &delete_stmt, nullptr);
322 if (ret != SQLITE_OK) {
323 /* LCOV_EXCL_START */
324 LOGE("sqlite3_prepare_v2 Failed [%d][%s]", ret, sqlite3_errmsg(db));
329 while (sqlite3_step(stmt) == SQLITE_ROW && count > 0) {
330 ret = sqlite3_bind_text(delete_stmt, 1,
331 reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)),
332 -1, SQLITE_TRANSIENT);
333 if (ret != SQLITE_OK) {
334 LOGE("sqlite3_bind_int() error: %d(%s)", ret, sqlite3_errmsg(db));
338 ret = sqlite3_step(delete_stmt);
339 if (ret != SQLITE_DONE) {
340 LOGE("step error: %d(%s)", ret, sqlite3_errmsg(db));
344 ret = sqlite3_reset(delete_stmt);
345 if (ret != SQLITE_OK) {
346 LOGE("sqlite3_reset() error: %d", ret);
350 sqlite3_clear_bindings(delete_stmt);
357 sqlite3_finalize(stmt);
359 sqlite3_finalize(delete_stmt);
364 int DBManager::UpdateReceiverList
365 (shared_ptr<item::AbstractItem> updatedItem, sqlite3* db) {
369 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid();
371 query = sqlite3_mprintf("DELETE FROM receiver_list"
372 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
373 updatedItem->GetId().c_str(), updatedItem->GetSenderAppId().c_str(),
376 LOGE("OOM - sql query");
377 return ERROR_OUT_OF_MEMORY;
380 ret = ExecuteQuery(db, query, nullptr);
383 if (ret != ERROR_NONE)
386 for (auto& i : updatedItem->GetReceiverList()) {
387 query = sqlite3_mprintf("INSERT INTO receiver_list"
388 " (root_id, app_id, uid, receiver_group)"
389 " VALUES (%Q, %Q, %d, %Q)",
390 updatedItem->GetId().c_str(),
391 updatedItem->GetSenderAppId().c_str(),
396 LOGE("OOM - sql query");
397 return ERROR_OUT_OF_MEMORY;
400 ret = ExecuteQuery(db, query, nullptr);
403 if (ret != ERROR_NONE)
409 int DBManager::InsertNotification(list<shared_ptr<item::AbstractItem>> addedItem) {
410 int ret = ERROR_NONE;
414 sqlite3* db = OpenDB();
417 return ERROR_FROM_DB;
419 if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
420 LOGE("begin transaction error : %s", sqlite3_errmsg(db));
422 return ERROR_FROM_DB;
425 for (auto& i : addedItem) {
426 uid_t uid = static_pointer_cast<IItemInfoInternal>(i->GetInfo())->GetUid();
427 ret = GetCount(0, i->GetId(), i->GetSenderAppId(), uid, &count);
428 if (ret != ERROR_NONE)
432 LOGE("already exist id :[%s] appid[%s]",
433 i->GetId().c_str(), i->GetSenderAppId().c_str());
434 ret = ERROR_ALREADY_EXIST_ID;
438 ret = GetSequence(db, &seq);
439 if (ret != ERROR_NONE)
442 static_pointer_cast<IItemInfoInternal>(i->GetInfo())->SetPrivateId(seq);
443 Bundle b = i->Serialize();
444 query = sqlite3_mprintf("INSERT INTO noti_ex_list"
445 " (root_id, app_id, uid, channel, priv_id, pkg_id, policy, data, insert_time)"
446 " VALUES (%Q, %Q, %d, %Q, %" PRId64 ", %Q, %d, %Q, %d)",
448 i->GetSenderAppId().c_str(),
450 i->GetChannel().c_str(),
451 static_pointer_cast<IItemInfoInternal>(i->GetInfo())->GetPrivateId(),
452 GetPkgId(i->GetSenderAppId(), uid).c_str(),
453 static_cast<int>(i->GetPolicy()),
454 reinterpret_cast<char*>(b.ToRaw().first.get()),
455 static_pointer_cast<IItemInfo>(i->GetInfo())->GetTime());
458 LOGE("OOM - sql query");
459 ret = ERROR_OUT_OF_MEMORY;
463 ret = ExecuteQuery(db, query, nullptr);
465 if (ret != ERROR_NONE)
468 ret = UpdateReceiverList(i, db);
469 if (ret != ERROR_NONE)
473 if (ret == ERROR_NONE) {
474 CheckLimit(*(addedItem.begin()), db);
475 if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
476 LOGE("end transaction error : %s", sqlite3_errmsg(db));
480 if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
481 LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
488 map<string, string> DBManager::GetHideMap() {
489 map<string, string> hide_map;
496 query = sqlite3_mprintf("SELECT root_id, app_id, uid, hide_list FROM noti_ex_list"
497 " WHERE hide_list IS NOT NULL");
499 LOGE("OOM - sql query");
509 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
510 if (ret != SQLITE_OK) {
511 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
518 while (sqlite3_step(stmt) == SQLITE_ROW) {
519 key = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) \
520 + string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) \
521 + string(to_string(sqlite3_column_int(stmt, 2)));
522 hide_map[key] = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
525 sqlite3_finalize(stmt);
530 int DBManager::GetCount(const string& app_id, uid_t uid, int* count) {
531 return GetCount(0, string(), app_id, uid, count);
534 int DBManager::GetCount(int64_t priv_id, const string& root_id, const string& app_id,
535 uid_t uid, int* count) {
542 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
543 " WHERE priv_id = %" PRId64 "", priv_id);
544 } else if (root_id.empty()) {
545 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
546 " WHERE app_id = %Q AND uid = %d", app_id.c_str(), uid);
548 query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
549 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
550 root_id.c_str(), app_id.c_str(), uid);
553 LOGE("OOM - sql query");
554 return ERROR_OUT_OF_MEMORY;
560 return ERROR_FROM_DB;
563 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
564 if (ret != SQLITE_OK) {
565 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
568 return ERROR_FROM_DB;
572 ret = sqlite3_step(stmt);
573 if (ret == SQLITE_ROW)
574 *count = sqlite3_column_int(stmt, 0);
578 sqlite3_finalize(stmt);
583 int DBManager::UpdateHideList(shared_ptr<item::AbstractItem> updatedItem,
584 const string& hide_list) {
588 query = sqlite3_mprintf("UPDATE noti_ex_list SET hide_list = %Q"
589 " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
590 hide_list.c_str(), updatedItem->GetId().c_str(),
591 updatedItem->GetSenderAppId().c_str(),
592 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid());
594 LOGE("OOM - sql query");
595 return ERROR_OUT_OF_MEMORY;
598 ret = ExecuteQuery(query, nullptr);
604 int DBManager::UpdateNotification(shared_ptr<item::AbstractItem> updatedItem) {
608 static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid();
609 int64_t priv_id = static_pointer_cast<IItemInfoInternal>(
610 updatedItem->GetInfo())->GetPrivateId();
612 ret = GetCount(priv_id,
613 updatedItem->GetId(), updatedItem->GetSenderAppId(), uid, &count);
614 if (ret != ERROR_NONE) {
615 LOGE("fail to get count");
620 LOGE("not exist priv_id(%" PRId64 ") id(%s) for appid(%s)", priv_id,
621 updatedItem->GetId().c_str(), updatedItem->GetSenderAppId().c_str());
622 return ERROR_NOT_EXIST_ID;
625 sqlite3* db = OpenDB();
627 return ERROR_FROM_DB;
629 Bundle b = updatedItem->Serialize();
630 query = sqlite3_mprintf("UPDATE noti_ex_list SET"
631 " pkg_id = %Q, channel = %Q, policy = %d, data = %Q, insert_time = %d"
632 " WHERE priv_id = %" PRId64 "",
633 GetPkgId(updatedItem->GetSenderAppId(), uid).c_str(),
634 updatedItem->GetChannel().c_str(),
635 static_cast<int>(updatedItem->GetPolicy()),
636 reinterpret_cast<char*>(b.ToRaw().first.get()),
637 static_pointer_cast<IItemInfo>(updatedItem->GetInfo())->GetTime(),
641 LOGE("OOM - sql query");
643 return ERROR_OUT_OF_MEMORY;
646 if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
647 LOGE("begin transaction error : %s", sqlite3_errmsg(db));
650 return ERROR_FROM_DB;
653 ret = ExecuteQuery(db, query, nullptr);
655 if (ret != ERROR_NONE)
658 ret = UpdateReceiverList(updatedItem, db);
661 if (ret == ERROR_NONE) {
662 if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
663 LOGE("end transaction error : %s", sqlite3_errmsg(db));
667 if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
668 LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
675 list<shared_ptr<item::AbstractItem>> DBManager::ExecuteGetList(char* query) {
679 list<shared_ptr<item::AbstractItem>> item_list;
682 LOGE("Invalid parameter");
690 ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
691 if (ret != SQLITE_OK) {
692 LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
697 while (sqlite3_step(stmt) == SQLITE_ROW) {
698 LOGE("[%s]", sqlite3_column_text(stmt, 0));
700 Bundle serialized(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
701 shared_ptr<item::AbstractItem> gen_item = item::ItemInflator::Create(serialized);
702 item_list.emplace_back(gen_item);
705 sqlite3_finalize(stmt);
710 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(
711 string app_id, uid_t uid) {
713 list<shared_ptr<item::AbstractItem>> item_list;
715 query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
716 " WHERE uid = %d AND app_id = %Q ORDER BY insert_time DESC",
717 uid, app_id.c_str());
719 LOGE("OOM - sql query");
723 item_list = ExecuteGetList(query);
729 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList
730 (string app_id, string root_id, uid_t uid) {
732 list<shared_ptr<item::AbstractItem>> item_list;
734 query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
735 " WHERE uid = %d AND app_id = %Q AND root_id = %Q",
736 uid, app_id.c_str(), root_id.c_str());
739 LOGE("OOM - sql query");
743 item_list = ExecuteGetList(query);
749 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList
750 (string app_id, int64_t priv_id, uid_t uid) {
752 list<shared_ptr<item::AbstractItem>> item_list;
754 query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
755 " WHERE uid = %d AND app_id = %Q AND priv_id = %" PRId64 "",
756 uid, app_id.c_str(), priv_id);
759 LOGE("OOM - sql query");
763 item_list = ExecuteGetList(query);
769 list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(
770 uid_t uid, string channel) {
773 list<shared_ptr<item::AbstractItem>> item_list;
775 /* Check current sim status */
776 ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &sim_mode);
778 sim_mode = VCONFKEY_TELEPHONY_SIM_INSERTED;
779 LOGI("vconf_get_int");
782 string channel_query;
783 if (!channel.empty())
784 channel_query = " AND channel = '" + channel + "' ";
786 string simmode_query;
787 if (sim_mode != VCONFKEY_TELEPHONY_SIM_INSERTED) {
788 simmode_query = " AND (policy & " +
789 to_string(static_cast<int>(item::AbstractItem::Policy::SimMode)) +
793 string query_str = "SELECT data FROM noti_ex_list WHERE uid = %d " +
797 query = sqlite3_mprintf(query_str.c_str(), uid);
799 LOGE("OOM - sql query");
803 item_list = ExecuteGetList(query);
809 int DBManager::DeleteNotification(shared_ptr<item::AbstractItem> deletedItem) {
812 int64_t priv_id = static_pointer_cast<IItemInfoInternal>(
813 deletedItem->GetInfo())->GetPrivateId();
815 query = sqlite3_mprintf("DELETE FROM noti_ex_list WHERE priv_id = %" PRId64 "",
818 LOGE("OOM - sql query");
819 return ERROR_OUT_OF_MEMORY;
822 ret = ExecuteQuery(query, nullptr);
827 string DBManager::GetPkgId(const string& app_id, uid_t uid) {
828 pkgmgrinfo_pkginfo_h handle;
832 if (pkgmgrinfo_appinfo_get_usr_appinfo(app_id.c_str(), uid, &handle) == PMINFO_R_OK) {
833 if (pkgmgrinfo_appinfo_get_pkgid(handle, &buf) == PMINFO_R_OK) {
837 pkgmgrinfo_appinfo_destroy_appinfo(handle);
841 } // namespace notification