/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "reminder_store.h" #include #include #include #include #include "ability_context.h" #include "ans_log_wrapper.h" #include "reminder_table.h" #include "reminder_request_alarm.h" #include "reminder_request_calendar.h" #include "reminder_request_timer.h" namespace OHOS { namespace Notification { namespace { const int32_t REMINDER_RDB_VERSION_V1 = 1; const int32_t REMINDER_RDB_VERSION_V2 = 2; const int32_t REMINDER_RDB_VERSION_V3 = 3; const uint32_t REMINDER_RDB_VERSION = 4; const int32_t STATE_FAIL = -1; std::string g_sqlColumns; } const int32_t ReminderStore::STATE_OK = 0; const std::string ReminderStore::REMINDER_DB_DIR = "/data/service/el1/public/notification/"; const std::string ReminderStore::REMINDER_DB_NAME = "notification.db"; const std::string ReminderStore::REMINDER_DB_TABLE = "reminder"; int32_t ReminderStore::ReminderStoreDataCallBack::OnCreate(NativeRdb::RdbStore &store) { ANSR_LOGD("Create table."); std::string CREATE_REMINDER_TABLE = "CREATE TABLE IF NOT EXISTS " + REMINDER_DB_TABLE + " (" + ReminderTable::sqlOfAddColumns + ")"; ANSR_LOGD("CreateTable:%{public}s", CREATE_REMINDER_TABLE.c_str()); return store.ExecuteSql(CREATE_REMINDER_TABLE); } int32_t ReminderStore::ReminderStoreDataCallBack::OnUpgrade( NativeRdb::RdbStore &store, int32_t oldVersion, int32_t newVersion) { ANSR_LOGI("OnUpgrade oldVersion is %{public}d, newVersion is %{public}d", oldVersion, newVersion); if (oldVersion < newVersion && newVersion == REMINDER_RDB_VERSION) { if (oldVersion == REMINDER_RDB_VERSION_V1) { AddRdbColum(store, "groupId", "TEXT"); AddRdbColum(store, "custom_ring_uri", "TEXT"); AddRdbColum(store, "snooze_slot_id", "INT"); AddRdbColum(store, "creator_bundle_name", "TEXT"); } else if (oldVersion == REMINDER_RDB_VERSION_V2) { AddRdbColum(store, "custom_ring_uri", "TEXT"); AddRdbColum(store, "snooze_slot_id", "INT"); AddRdbColum(store, "creator_bundle_name", "TEXT"); } else if (oldVersion == REMINDER_RDB_VERSION_V3) { AddRdbColum(store, "creator_bundle_name", "TEXT"); } } store.SetVersion(newVersion); return NativeRdb::E_OK; } __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Init() { ANSR_LOGD("Reminder store init."); int32_t errCode(STATE_FAIL); if (access(REMINDER_DB_DIR.c_str(), F_OK) != 0) { int createDir = mkdir(REMINDER_DB_DIR.c_str(), S_IRWXU); if (createDir != 0) { ANSR_LOGE("Failed to create directory %{public}s", REMINDER_DB_DIR.c_str()); return errCode; } } ReminderTable::InitDbColumns(); for (std::vector::const_iterator it = ReminderTable::columns.begin(); it != ReminderTable::columns.end(); ++it) { g_sqlColumns += *it + ","; } g_sqlColumns = g_sqlColumns.substr(0, g_sqlColumns.size() - 1); ANSR_LOGD("ReminderStore g_sqlColumns =%{public}s", g_sqlColumns.c_str()); std::string dbConfig = REMINDER_DB_DIR + REMINDER_DB_NAME; NativeRdb::RdbStoreConfig config_(dbConfig); config_.SetSecurityLevel(NativeRdb::SecurityLevel::S1); ReminderStoreDataCallBack rdbDataCallBack_; rdbStore_ = NativeRdb::RdbHelper::GetRdbStore(config_, REMINDER_RDB_VERSION, rdbDataCallBack_, errCode); if (rdbStore_ == nullptr) { ANSR_LOGE("ReminderStore init fail, errCode %{public}d.", errCode); return errCode; } return ReminderStore::InitData(); } __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::InitData() { ANSR_LOGD("Reminder data init."); if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return STATE_FAIL; } std::string deleteCondition = ReminderTable::IS_EXPIRED + " is true"; ReminderStore::Delete(deleteCondition); int32_t statusChangedRows = STATE_FAIL; NativeRdb::ValuesBucket statusValues; statusValues.PutInt(ReminderTable::STATE, ReminderRequest::REMINDER_STATUS_INACTIVE); int32_t statusResult = rdbStore_->Update(statusChangedRows, REMINDER_DB_TABLE, statusValues); ANSR_LOGD("Change status to inactive, changed rows: %{public}d.", statusChangedRows); if (statusResult != NativeRdb::E_OK) { ANSR_LOGE("Init data failed."); return STATE_FAIL; } int32_t activeChangedRows = STATE_FAIL; NativeRdb::ValuesBucket activeValues; activeValues.PutString(ReminderTable::IS_ACTIVE, "false"); std::string activeUpdateCondition = ReminderTable::IS_ACTIVE + " is true"; std::vector activeWhereArgs; int32_t activeResult = rdbStore_->Update( activeChangedRows, REMINDER_DB_TABLE, activeValues, activeUpdateCondition, activeWhereArgs); ANSR_LOGD("Change status isActive to false, changed rows: %{public}d.", activeChangedRows); if (activeResult != NativeRdb::E_OK) { ANSR_LOGE("Init data failed."); return STATE_FAIL; } int32_t scheduledChangedRows = STATE_FAIL; NativeRdb::ValuesBucket scheduledValues; scheduledValues.PutString(ReminderTable::HAS_SCHEDULED_TIMEOUT, "false"); std::string scheduledUpdateCondition = ReminderTable::HAS_SCHEDULED_TIMEOUT + " is true"; std::vector scheduledWhereArgs; int32_t scheduledResult = rdbStore_->Update( scheduledChangedRows, REMINDER_DB_TABLE, scheduledValues, scheduledUpdateCondition, scheduledWhereArgs); ANSR_LOGD("Change status has_ScheduledTimeout to false, changed rows: %{public}d.", scheduledChangedRows); if (scheduledResult != NativeRdb::E_OK) { ANSR_LOGE("Init data failed."); return STATE_FAIL; } return ReminderStore::STATE_OK; } __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Delete(int32_t reminderId) { std::string deleteCondition = ReminderTable ::REMINDER_ID + " = " + std::to_string(reminderId); return ReminderStore::Delete(deleteCondition); } int32_t ReminderStore::DeleteUser(int32_t userId) { std::string deleteCondition = ReminderTable::USER_ID + " = " + std::to_string(userId); return ReminderStore::Delete(deleteCondition); } __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Delete(const std::string &pkg, int32_t userId) { std::string deleteCondition = ReminderTable::PKG_NAME + " = \"" + pkg + "\" and " + ReminderTable::USER_ID + " = " + std::to_string(userId); return ReminderStore::Delete(deleteCondition); } __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Delete(const std::string &deleteCondition) { if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return STATE_FAIL; } int32_t deletedRows = STATE_FAIL; std::vector whereArgs; int32_t result = rdbStore_->Delete(deletedRows, REMINDER_DB_TABLE, deleteCondition, whereArgs); if (result != NativeRdb::E_OK) { ANSR_LOGE("Delete operation failed, deleteConditon: %{public}s," \ "result: %{public}d.", deleteCondition.c_str(), result); } ANSR_LOGD("Delete operation done, deleteConditon: %{public}s," \ "deleted rows: %{public}d.", deleteCondition.c_str(), deletedRows); return deletedRows; } int64_t ReminderStore::UpdateOrInsert( const sptr &reminder, const sptr &bundleOption) { if (reminder->GetReminderType() == ReminderRequest::ReminderType::TIMER) { ANSR_LOGI("Countdown not support persist."); return STATE_FAIL; } int64_t isSuccess = STATE_FAIL; if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return isSuccess; } if (bundleOption == nullptr) { ANSR_LOGE("BundleOption is null."); return isSuccess; } if (IsReminderExist(reminder)) { isSuccess = Update(reminder, bundleOption); } else { isSuccess = Insert(reminder, bundleOption); } return isSuccess; } int64_t ReminderStore::Insert( const sptr &reminder, const sptr &bundleOption) { if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return STATE_FAIL; } int64_t rowId = STATE_FAIL; NativeRdb::ValuesBucket values; ReminderStore::GenerateData(reminder, bundleOption, values); int32_t result = rdbStore_->Insert(rowId, REMINDER_DB_TABLE, values); if (result != NativeRdb::E_OK) { ANSR_LOGE("Insert operation failed, result: %{public}d, reminderId=%{public}d.", result, reminder->GetReminderId()); return result; } ANSR_LOGD("Insert successfully, reminderId=%{public}d.", reminder->GetReminderId()); return result; } int64_t ReminderStore::Update( const sptr &reminder, const sptr &bundleOption) { if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return STATE_FAIL; } int32_t changedRows = STATE_FAIL; NativeRdb::ValuesBucket values; ReminderStore::GenerateData(reminder, bundleOption, values); std::string updateCondition = ReminderTable::REMINDER_ID + " = " + std::to_string(reminder->GetReminderId()); std::vector whereArgs; int32_t result = rdbStore_->Update(changedRows, REMINDER_DB_TABLE, values, updateCondition, whereArgs); if ((result != NativeRdb::E_OK) || (changedRows <= 0)) { ANSR_LOGE("Update operation failed, result: %{public}d, updated rows: %{public}d, reminderId=%{public}d.", result, changedRows, reminder->GetReminderId()); return result; } ANSR_LOGD("Update successfully, updated rows: %{public}d, reminderId=%{public}d.", changedRows, reminder->GetReminderId()); return result; } bool ReminderStore::IsReminderExist(const sptr &reminder) { NativeRdb::AbsRdbPredicates absRdbPredicates(REMINDER_DB_TABLE); absRdbPredicates.EqualTo(ReminderTable::REMINDER_ID, std::to_string(reminder->GetReminderId())); auto queryResultSet = rdbStore_->Query(absRdbPredicates, std::vector()); if (queryResultSet == nullptr) { ANSR_LOGE("QueryResultSet is null."); return false; } int32_t resultNum; queryResultSet->GetRowCount(resultNum); if (resultNum == 0) { return false; } return true; } std::shared_ptr ReminderStore::Query(const std::string &queryCondition) const { if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return nullptr; } std::vector whereArgs; return rdbStore_->QuerySql(queryCondition, whereArgs); } int32_t ReminderStore::GetMaxId() { if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return STATE_FAIL; } std::string queryCondition = "select " + ReminderTable::REMINDER_ID + " from " + REMINDER_DB_TABLE + " order by " + ReminderTable::REMINDER_ID + " desc"; auto queryResultSet = ReminderStore::Query(queryCondition); if (queryResultSet == nullptr) { ANSR_LOGE("QueryResultSet is null."); return STATE_FAIL; } int32_t resultNum; queryResultSet->GetRowCount(resultNum); if (resultNum == 0) { ANSR_LOGI("QueryResultSet is zero."); return STATE_FAIL; } queryResultSet->GoToNextRow(); int32_t maxId = STATE_FAIL; int32_t result = queryResultSet->GetInt(0, maxId); if (result != NativeRdb::E_OK) { ANSR_LOGE("Query operation failed, result %{public}d.", result); } ANSR_LOGD("MaxId: %{public}d.", maxId); return maxId; } __attribute__((no_sanitize("cfi"))) std::vector> ReminderStore::GetAllValidReminders() { std::string sql = "select " + g_sqlColumns + " from " + REMINDER_DB_TABLE + " where " + ReminderTable::IS_EXPIRED + " = 'false' order by " + ReminderTable::TRIGGER_TIME + " asc"; ANSR_LOGD("GetAllValidReminders sql =%{public}s", sql.c_str()); return GetReminders(sql); } std::vector> ReminderStore::GetReminders(const std::string &queryCondition) { std::vector> reminders; if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return reminders; } auto queryResultSet = Query(queryCondition); if (queryResultSet == nullptr) { return reminders; } bool isAtLastRow = false; queryResultSet->IsAtLastRow(isAtLastRow); while (!isAtLastRow) { queryResultSet->GoToNextRow(); sptr reminder = BuildReminder(queryResultSet); if (reminder != nullptr) { reminders.push_back(reminder); } queryResultSet->IsAtLastRow(isAtLastRow); } ANSR_LOGD("Size=%{public}zu", reminders.size()); return reminders; } sptr ReminderStore::BuildReminder(const std::shared_ptr &resultSet) { int32_t reminderType; int32_t reminderId; GetInt32Val(resultSet, ReminderTable::REMINDER_TYPE, reminderType); GetInt32Val(resultSet, ReminderTable::REMINDER_ID, reminderId); sptr reminder = nullptr; switch (reminderType) { case (static_cast(ReminderRequest::ReminderType::TIMER)): { reminder = new (std::nothrow) ReminderRequestTimer(reminderId); break; } case (static_cast(ReminderRequest::ReminderType::CALENDAR)): { reminder = new (std::nothrow) ReminderRequestCalendar(reminderId); break; } case (static_cast(ReminderRequest::ReminderType::ALARM)): { reminder = new (std::nothrow) ReminderRequestAlarm(reminderId); break; } default: { ANSR_LOGE("ReminderType from database is error, reminderType %{public}d.", reminderType); break; } } if (reminder != nullptr) { reminder->RecoverFromDb(resultSet); ANSR_LOGI("BuildReminder success."); } else { ANSR_LOGW("BuildReminder fail."); } return reminder; } bool ReminderStore::GetBundleOption(const int32_t &reminderId, sptr &bundleOption) const { if (rdbStore_ == nullptr) { ANSR_LOGE("Rdb store is not initialized."); return false; } NativeRdb::AbsRdbPredicates absRdbPredicates(REMINDER_DB_TABLE); absRdbPredicates.EqualTo(ReminderTable ::REMINDER_ID, std::to_string(reminderId)); std::shared_ptr queryResultSet = rdbStore_->Query(absRdbPredicates, std::vector()); if (queryResultSet == nullptr) { return false; } bool isAtLastRow = false; queryResultSet->IsAtLastRow(isAtLastRow); if (isAtLastRow) { return false; } queryResultSet->GoToNextRow(); std::string pkgName; GetStringVal(queryResultSet, ReminderTable ::PKG_NAME, pkgName); int32_t uid; GetInt32Val(queryResultSet, ReminderTable::UID, uid); bundleOption->SetBundleName(pkgName); bundleOption->SetUid(uid); return true; } void ReminderStore::GetInt32Val(const std::shared_ptr &resultSet, const std::string &name, int32_t &value) { int32_t columnIndex = -1; resultSet->GetColumnIndex(name, columnIndex); if (columnIndex == -1) { ANSR_LOGE("the column %{public}s does not exsit.", name.c_str()); return; } resultSet->GetInt(columnIndex, value); } void ReminderStore::GetInt64Val(const std::shared_ptr& resultSet, const std::string& name, int64_t& value) { int32_t columnIndex = -1; resultSet->GetColumnIndex(name, columnIndex); if (columnIndex == -1) { ANSR_LOGE("the column %{public}s does not exsit.", name.c_str()); return; } resultSet->GetLong(columnIndex, value); } void ReminderStore::GetStringVal(const std::shared_ptr &resultSet, const std::string &name, std::string &value) { int32_t columnIndex = -1; resultSet->GetColumnIndex(name, columnIndex); if (columnIndex == -1) { ANSR_LOGE("the column %{public}s does not exsit.", name.c_str()); return; } resultSet->GetString(columnIndex, value); } void ReminderStore::GenerateData(const sptr &reminder, const sptr &bundleOption, NativeRdb::ValuesBucket &values) const { ReminderRequest::AppendValuesBucket(reminder, bundleOption, values); ReminderRequestCalendar::AppendValuesBucket(reminder, bundleOption, values); ReminderRequestAlarm::AppendValuesBucket(reminder, bundleOption, values); } void ReminderStore::AddRdbColum(NativeRdb::RdbStore &store, const std::string &columName, const std::string &type) { std::string sqlStr = ""; if (type == "TEXT") { sqlStr = "ALTER TABLE " + REMINDER_DB_TABLE + " ADD " + columName + " " + type + " DEFAULT '';"; } else if (type == "INT") { //3 is meaning others sqlStr = "ALTER TABLE " + REMINDER_DB_TABLE + " ADD " + columName + " " + type + " DEFAULT 3;"; } ANSR_LOGD("AddRdbColum sqlStr = %{public}s", sqlStr.c_str()); int errorCode = store.ExecuteSql(sqlStr); if (errorCode != NativeRdb::E_OK) { ANSR_LOGE("AddRdbColum error,errorCode is = %{public}d", errorCode); }; } } // namespace Notification } // namespace OHOS