1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "reminder_store.h"
17
18 #include <filesystem>
19 #include <sstream>
20 #include <sys/stat.h>
21 #include <unistd.h>
22
23 #include "ability_context.h"
24 #include "ans_log_wrapper.h"
25 #include "reminder_table.h"
26 #include "reminder_request_alarm.h"
27 #include "reminder_request_calendar.h"
28 #include "reminder_request_timer.h"
29
30 namespace OHOS {
31 namespace Notification {
32 namespace {
33 const int32_t REMINDER_RDB_VERSION_V1 = 1;
34 const int32_t REMINDER_RDB_VERSION_V2 = 2;
35 const int32_t REMINDER_RDB_VERSION_V3 = 3;
36 const uint32_t REMINDER_RDB_VERSION = 4;
37 const int32_t STATE_FAIL = -1;
38 std::string g_sqlColumns;
39 }
40
41 const int32_t ReminderStore::STATE_OK = 0;
42 const std::string ReminderStore::REMINDER_DB_DIR = "/data/service/el1/public/notification/";
43 const std::string ReminderStore::REMINDER_DB_NAME = "notification.db";
44 const std::string ReminderStore::REMINDER_DB_TABLE = "reminder";
45
OnCreate(NativeRdb::RdbStore & store)46 int32_t ReminderStore::ReminderStoreDataCallBack::OnCreate(NativeRdb::RdbStore &store)
47 {
48 ANSR_LOGD("Create table.");
49 std::string CREATE_REMINDER_TABLE = "CREATE TABLE IF NOT EXISTS " + REMINDER_DB_TABLE + " ("
50 + ReminderTable::sqlOfAddColumns + ")";
51 ANSR_LOGD("CreateTable:%{public}s", CREATE_REMINDER_TABLE.c_str());
52 return store.ExecuteSql(CREATE_REMINDER_TABLE);
53 }
54
OnUpgrade(NativeRdb::RdbStore & store,int32_t oldVersion,int32_t newVersion)55 int32_t ReminderStore::ReminderStoreDataCallBack::OnUpgrade(
56 NativeRdb::RdbStore &store, int32_t oldVersion, int32_t newVersion)
57 {
58 ANSR_LOGI("OnUpgrade oldVersion is %{public}d, newVersion is %{public}d", oldVersion, newVersion);
59 if (oldVersion < newVersion && newVersion == REMINDER_RDB_VERSION) {
60 if (oldVersion == REMINDER_RDB_VERSION_V1) {
61 AddRdbColum(store, "groupId", "TEXT");
62 AddRdbColum(store, "custom_ring_uri", "TEXT");
63 AddRdbColum(store, "snooze_slot_id", "INT");
64 AddRdbColum(store, "creator_bundle_name", "TEXT");
65 } else if (oldVersion == REMINDER_RDB_VERSION_V2) {
66 AddRdbColum(store, "custom_ring_uri", "TEXT");
67 AddRdbColum(store, "snooze_slot_id", "INT");
68 AddRdbColum(store, "creator_bundle_name", "TEXT");
69 } else if (oldVersion == REMINDER_RDB_VERSION_V3) {
70 AddRdbColum(store, "creator_bundle_name", "TEXT");
71 }
72 }
73 store.SetVersion(newVersion);
74 return NativeRdb::E_OK;
75 }
76
Init()77 __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Init()
78 {
79 ANSR_LOGD("Reminder store init.");
80 int32_t errCode(STATE_FAIL);
81
82 if (access(REMINDER_DB_DIR.c_str(), F_OK) != 0) {
83 int createDir = mkdir(REMINDER_DB_DIR.c_str(), S_IRWXU);
84 if (createDir != 0) {
85 ANSR_LOGE("Failed to create directory %{public}s", REMINDER_DB_DIR.c_str());
86 return errCode;
87 }
88 }
89
90 ReminderTable::InitDbColumns();
91 for (std::vector<std::string>::const_iterator it = ReminderTable::columns.begin();
92 it != ReminderTable::columns.end();
93 ++it) {
94 g_sqlColumns += *it + ",";
95 }
96 g_sqlColumns = g_sqlColumns.substr(0, g_sqlColumns.size() - 1);
97 ANSR_LOGD("ReminderStore g_sqlColumns =%{public}s", g_sqlColumns.c_str());
98
99 std::string dbConfig = REMINDER_DB_DIR + REMINDER_DB_NAME;
100 NativeRdb::RdbStoreConfig config_(dbConfig);
101 config_.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
102 ReminderStoreDataCallBack rdbDataCallBack_;
103 rdbStore_ = NativeRdb::RdbHelper::GetRdbStore(config_, REMINDER_RDB_VERSION, rdbDataCallBack_, errCode);
104 if (rdbStore_ == nullptr) {
105 ANSR_LOGE("ReminderStore init fail, errCode %{public}d.", errCode);
106 return errCode;
107 }
108 return ReminderStore::InitData();
109 }
110
InitData()111 __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::InitData()
112 {
113 ANSR_LOGD("Reminder data init.");
114 if (rdbStore_ == nullptr) {
115 ANSR_LOGE("Rdb store is not initialized.");
116 return STATE_FAIL;
117 }
118 std::string deleteCondition = ReminderTable::IS_EXPIRED + " is true";
119 ReminderStore::Delete(deleteCondition);
120
121 int32_t statusChangedRows = STATE_FAIL;
122 NativeRdb::ValuesBucket statusValues;
123 statusValues.PutInt(ReminderTable::STATE, ReminderRequest::REMINDER_STATUS_INACTIVE);
124 int32_t statusResult = rdbStore_->Update(statusChangedRows, REMINDER_DB_TABLE, statusValues);
125 ANSR_LOGD("Change status to inactive, changed rows: %{public}d.", statusChangedRows);
126 if (statusResult != NativeRdb::E_OK) {
127 ANSR_LOGE("Init data failed.");
128 return STATE_FAIL;
129 }
130
131 int32_t activeChangedRows = STATE_FAIL;
132 NativeRdb::ValuesBucket activeValues;
133 activeValues.PutString(ReminderTable::IS_ACTIVE, "false");
134 std::string activeUpdateCondition = ReminderTable::IS_ACTIVE + " is true";
135 std::vector<std::string> activeWhereArgs;
136 int32_t activeResult = rdbStore_->Update(
137 activeChangedRows, REMINDER_DB_TABLE, activeValues, activeUpdateCondition, activeWhereArgs);
138 ANSR_LOGD("Change status isActive to false, changed rows: %{public}d.", activeChangedRows);
139 if (activeResult != NativeRdb::E_OK) {
140 ANSR_LOGE("Init data failed.");
141 return STATE_FAIL;
142 }
143
144 int32_t scheduledChangedRows = STATE_FAIL;
145 NativeRdb::ValuesBucket scheduledValues;
146 scheduledValues.PutString(ReminderTable::HAS_SCHEDULED_TIMEOUT, "false");
147 std::string scheduledUpdateCondition = ReminderTable::HAS_SCHEDULED_TIMEOUT + " is true";
148 std::vector<std::string> scheduledWhereArgs;
149 int32_t scheduledResult = rdbStore_->Update(
150 scheduledChangedRows, REMINDER_DB_TABLE, scheduledValues, scheduledUpdateCondition, scheduledWhereArgs);
151 ANSR_LOGD("Change status has_ScheduledTimeout to false, changed rows: %{public}d.", scheduledChangedRows);
152 if (scheduledResult != NativeRdb::E_OK) {
153 ANSR_LOGE("Init data failed.");
154 return STATE_FAIL;
155 }
156 return ReminderStore::STATE_OK;
157 }
158
Delete(int32_t reminderId)159 __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Delete(int32_t reminderId)
160 {
161 std::string deleteCondition = ReminderTable ::REMINDER_ID
162 + " = " + std::to_string(reminderId);
163 return ReminderStore::Delete(deleteCondition);
164 }
165
DeleteUser(int32_t userId)166 int32_t ReminderStore::DeleteUser(int32_t userId)
167 {
168 std::string deleteCondition = ReminderTable::USER_ID + " = " + std::to_string(userId);
169 return ReminderStore::Delete(deleteCondition);
170 }
171
Delete(const std::string & pkg,int32_t userId)172 __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Delete(const std::string &pkg, int32_t userId)
173 {
174 std::string deleteCondition = ReminderTable::PKG_NAME + " = \"" + pkg + "\" and "
175 + ReminderTable::USER_ID + " = " + std::to_string(userId);
176 return ReminderStore::Delete(deleteCondition);
177 }
178
Delete(const std::string & deleteCondition)179 __attribute__((no_sanitize("cfi"))) int32_t ReminderStore::Delete(const std::string &deleteCondition)
180 {
181 if (rdbStore_ == nullptr) {
182 ANSR_LOGE("Rdb store is not initialized.");
183 return STATE_FAIL;
184 }
185 int32_t deletedRows = STATE_FAIL;
186 std::vector<std::string> whereArgs;
187 int32_t result = rdbStore_->Delete(deletedRows, REMINDER_DB_TABLE, deleteCondition, whereArgs);
188 if (result != NativeRdb::E_OK) {
189 ANSR_LOGE("Delete operation failed, deleteConditon: %{public}s," \
190 "result: %{public}d.", deleteCondition.c_str(), result);
191 }
192 ANSR_LOGD("Delete operation done, deleteConditon: %{public}s," \
193 "deleted rows: %{public}d.", deleteCondition.c_str(), deletedRows);
194 return deletedRows;
195 }
196
UpdateOrInsert(const sptr<ReminderRequest> & reminder,const sptr<NotificationBundleOption> & bundleOption)197 int64_t ReminderStore::UpdateOrInsert(
198 const sptr<ReminderRequest> &reminder, const sptr<NotificationBundleOption> &bundleOption)
199 {
200 if (reminder->GetReminderType() == ReminderRequest::ReminderType::TIMER) {
201 ANSR_LOGI("Countdown not support persist.");
202 return STATE_FAIL;
203 }
204 int64_t isSuccess = STATE_FAIL;
205 if (rdbStore_ == nullptr) {
206 ANSR_LOGE("Rdb store is not initialized.");
207 return isSuccess;
208 }
209 if (bundleOption == nullptr) {
210 ANSR_LOGE("BundleOption is null.");
211 return isSuccess;
212 }
213 if (IsReminderExist(reminder)) {
214 isSuccess = Update(reminder, bundleOption);
215 } else {
216 isSuccess = Insert(reminder, bundleOption);
217 }
218 return isSuccess;
219 }
220
Insert(const sptr<ReminderRequest> & reminder,const sptr<NotificationBundleOption> & bundleOption)221 int64_t ReminderStore::Insert(
222 const sptr<ReminderRequest> &reminder, const sptr<NotificationBundleOption> &bundleOption)
223 {
224 if (rdbStore_ == nullptr) {
225 ANSR_LOGE("Rdb store is not initialized.");
226 return STATE_FAIL;
227 }
228 int64_t rowId = STATE_FAIL;
229 NativeRdb::ValuesBucket values;
230 ReminderStore::GenerateData(reminder, bundleOption, values);
231 int32_t result = rdbStore_->Insert(rowId, REMINDER_DB_TABLE, values);
232 if (result != NativeRdb::E_OK) {
233 ANSR_LOGE("Insert operation failed, result: %{public}d, reminderId=%{public}d.",
234 result, reminder->GetReminderId());
235 return result;
236 }
237 ANSR_LOGD("Insert successfully, reminderId=%{public}d.", reminder->GetReminderId());
238 return result;
239 }
240
Update(const sptr<ReminderRequest> & reminder,const sptr<NotificationBundleOption> & bundleOption)241 int64_t ReminderStore::Update(
242 const sptr<ReminderRequest> &reminder, const sptr<NotificationBundleOption> &bundleOption)
243 {
244 if (rdbStore_ == nullptr) {
245 ANSR_LOGE("Rdb store is not initialized.");
246 return STATE_FAIL;
247 }
248 int32_t changedRows = STATE_FAIL;
249 NativeRdb::ValuesBucket values;
250 ReminderStore::GenerateData(reminder, bundleOption, values);
251 std::string updateCondition = ReminderTable::REMINDER_ID
252 + " = " + std::to_string(reminder->GetReminderId());
253 std::vector<std::string> whereArgs;
254 int32_t result = rdbStore_->Update(changedRows, REMINDER_DB_TABLE, values, updateCondition, whereArgs);
255 if ((result != NativeRdb::E_OK) || (changedRows <= 0)) {
256 ANSR_LOGE("Update operation failed, result: %{public}d, updated rows: %{public}d, reminderId=%{public}d.",
257 result, changedRows, reminder->GetReminderId());
258 return result;
259 }
260 ANSR_LOGD("Update successfully, updated rows: %{public}d, reminderId=%{public}d.",
261 changedRows, reminder->GetReminderId());
262 return result;
263 }
264
IsReminderExist(const sptr<ReminderRequest> & reminder)265 bool ReminderStore::IsReminderExist(const sptr<ReminderRequest> &reminder)
266 {
267 NativeRdb::AbsRdbPredicates absRdbPredicates(REMINDER_DB_TABLE);
268 absRdbPredicates.EqualTo(ReminderTable::REMINDER_ID, std::to_string(reminder->GetReminderId()));
269 auto queryResultSet = rdbStore_->Query(absRdbPredicates, std::vector<std::string>());
270 if (queryResultSet == nullptr) {
271 ANSR_LOGE("QueryResultSet is null.");
272 return false;
273 }
274 int32_t resultNum;
275 queryResultSet->GetRowCount(resultNum);
276 if (resultNum == 0) {
277 return false;
278 }
279 return true;
280 }
281
Query(const std::string & queryCondition) const282 std::shared_ptr<NativeRdb::ResultSet> ReminderStore::Query(const std::string &queryCondition) const
283 {
284 if (rdbStore_ == nullptr) {
285 ANSR_LOGE("Rdb store is not initialized.");
286 return nullptr;
287 }
288 std::vector<std::string> whereArgs;
289 return rdbStore_->QuerySql(queryCondition, whereArgs);
290 }
291
292
GetMaxId()293 int32_t ReminderStore::GetMaxId()
294 {
295 if (rdbStore_ == nullptr) {
296 ANSR_LOGE("Rdb store is not initialized.");
297 return STATE_FAIL;
298 }
299 std::string queryCondition = "select " + ReminderTable::REMINDER_ID
300 + " from " + REMINDER_DB_TABLE + " order by "
301 + ReminderTable::REMINDER_ID + " desc";
302 auto queryResultSet = ReminderStore::Query(queryCondition);
303 if (queryResultSet == nullptr) {
304 ANSR_LOGE("QueryResultSet is null.");
305 return STATE_FAIL;
306 }
307 int32_t resultNum;
308 queryResultSet->GetRowCount(resultNum);
309 if (resultNum == 0) {
310 ANSR_LOGI("QueryResultSet is zero.");
311 return STATE_FAIL;
312 }
313 queryResultSet->GoToNextRow();
314 int32_t maxId = STATE_FAIL;
315 int32_t result = queryResultSet->GetInt(0, maxId);
316 if (result != NativeRdb::E_OK) {
317 ANSR_LOGE("Query operation failed, result %{public}d.", result);
318 }
319 ANSR_LOGD("MaxId: %{public}d.", maxId);
320 return maxId;
321 }
322
GetAllValidReminders()323 __attribute__((no_sanitize("cfi"))) std::vector<sptr<ReminderRequest>> ReminderStore::GetAllValidReminders()
324 {
325 std::string sql = "select " + g_sqlColumns + " from " + REMINDER_DB_TABLE + " where "
326 + ReminderTable::IS_EXPIRED + " = 'false' order by "
327 + ReminderTable::TRIGGER_TIME + " asc";
328 ANSR_LOGD("GetAllValidReminders sql =%{public}s", sql.c_str());
329 return GetReminders(sql);
330 }
331
GetReminders(const std::string & queryCondition)332 std::vector<sptr<ReminderRequest>> ReminderStore::GetReminders(const std::string &queryCondition)
333 {
334 std::vector<sptr<ReminderRequest>> reminders;
335 if (rdbStore_ == nullptr) {
336 ANSR_LOGE("Rdb store is not initialized.");
337 return reminders;
338 }
339 auto queryResultSet = Query(queryCondition);
340 if (queryResultSet == nullptr) {
341 return reminders;
342 }
343 bool isAtLastRow = false;
344 queryResultSet->IsAtLastRow(isAtLastRow);
345 while (!isAtLastRow) {
346 queryResultSet->GoToNextRow();
347 sptr<ReminderRequest> reminder = BuildReminder(queryResultSet);
348 if (reminder != nullptr) {
349 reminders.push_back(reminder);
350 }
351 queryResultSet->IsAtLastRow(isAtLastRow);
352 }
353 ANSR_LOGD("Size=%{public}zu", reminders.size());
354 return reminders;
355 }
356
BuildReminder(const std::shared_ptr<NativeRdb::ResultSet> & resultSet)357 sptr<ReminderRequest> ReminderStore::BuildReminder(const std::shared_ptr<NativeRdb::ResultSet> &resultSet)
358 {
359 int32_t reminderType;
360 int32_t reminderId;
361 GetInt32Val(resultSet, ReminderTable::REMINDER_TYPE, reminderType);
362 GetInt32Val(resultSet, ReminderTable::REMINDER_ID, reminderId);
363
364 sptr<ReminderRequest> reminder = nullptr;
365 switch (reminderType) {
366 case (static_cast<int32_t>(ReminderRequest::ReminderType::TIMER)): {
367 reminder = new (std::nothrow) ReminderRequestTimer(reminderId);
368 break;
369 }
370 case (static_cast<int32_t>(ReminderRequest::ReminderType::CALENDAR)): {
371 reminder = new (std::nothrow) ReminderRequestCalendar(reminderId);
372 break;
373 }
374 case (static_cast<int32_t>(ReminderRequest::ReminderType::ALARM)): {
375 reminder = new (std::nothrow) ReminderRequestAlarm(reminderId);
376 break;
377 }
378 default: {
379 ANSR_LOGE("ReminderType from database is error, reminderType %{public}d.", reminderType);
380 break;
381 }
382 }
383 if (reminder != nullptr) {
384 reminder->RecoverFromDb(resultSet);
385 ANSR_LOGI("BuildReminder success.");
386 } else {
387 ANSR_LOGW("BuildReminder fail.");
388 }
389 return reminder;
390 }
391
GetBundleOption(const int32_t & reminderId,sptr<NotificationBundleOption> & bundleOption) const392 bool ReminderStore::GetBundleOption(const int32_t &reminderId, sptr<NotificationBundleOption> &bundleOption) const
393 {
394 if (rdbStore_ == nullptr) {
395 ANSR_LOGE("Rdb store is not initialized.");
396 return false;
397 }
398 NativeRdb::AbsRdbPredicates absRdbPredicates(REMINDER_DB_TABLE);
399 absRdbPredicates.EqualTo(ReminderTable ::REMINDER_ID, std::to_string(reminderId));
400 std::shared_ptr<OHOS::NativeRdb::ResultSet> queryResultSet =
401 rdbStore_->Query(absRdbPredicates, std::vector<std::string>());
402 if (queryResultSet == nullptr) {
403 return false;
404 }
405 bool isAtLastRow = false;
406 queryResultSet->IsAtLastRow(isAtLastRow);
407 if (isAtLastRow) {
408 return false;
409 }
410 queryResultSet->GoToNextRow();
411 std::string pkgName;
412 GetStringVal(queryResultSet, ReminderTable ::PKG_NAME, pkgName);
413 int32_t uid;
414 GetInt32Val(queryResultSet, ReminderTable::UID, uid);
415 bundleOption->SetBundleName(pkgName);
416 bundleOption->SetUid(uid);
417 return true;
418 }
419
GetInt32Val(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const std::string & name,int32_t & value)420 void ReminderStore::GetInt32Val(const std::shared_ptr<NativeRdb::ResultSet> &resultSet,
421 const std::string &name, int32_t &value)
422 {
423 int32_t columnIndex = -1;
424 resultSet->GetColumnIndex(name, columnIndex);
425 if (columnIndex == -1) {
426 ANSR_LOGE("the column %{public}s does not exsit.", name.c_str());
427 return;
428 }
429 resultSet->GetInt(columnIndex, value);
430 }
431
GetInt64Val(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const std::string & name,int64_t & value)432 void ReminderStore::GetInt64Val(const std::shared_ptr<NativeRdb::ResultSet>& resultSet,
433 const std::string& name, int64_t& value)
434 {
435 int32_t columnIndex = -1;
436 resultSet->GetColumnIndex(name, columnIndex);
437 if (columnIndex == -1) {
438 ANSR_LOGE("the column %{public}s does not exsit.", name.c_str());
439 return;
440 }
441 resultSet->GetLong(columnIndex, value);
442 }
443
GetStringVal(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,const std::string & name,std::string & value)444 void ReminderStore::GetStringVal(const std::shared_ptr<NativeRdb::ResultSet> &resultSet,
445 const std::string &name, std::string &value)
446 {
447 int32_t columnIndex = -1;
448 resultSet->GetColumnIndex(name, columnIndex);
449 if (columnIndex == -1) {
450 ANSR_LOGE("the column %{public}s does not exsit.", name.c_str());
451 return;
452 }
453 resultSet->GetString(columnIndex, value);
454 }
455
GenerateData(const sptr<ReminderRequest> & reminder,const sptr<NotificationBundleOption> & bundleOption,NativeRdb::ValuesBucket & values) const456 void ReminderStore::GenerateData(const sptr<ReminderRequest> &reminder,
457 const sptr<NotificationBundleOption> &bundleOption, NativeRdb::ValuesBucket &values) const
458 {
459 ReminderRequest::AppendValuesBucket(reminder, bundleOption, values);
460 ReminderRequestCalendar::AppendValuesBucket(reminder, bundleOption, values);
461 ReminderRequestAlarm::AppendValuesBucket(reminder, bundleOption, values);
462 }
463
AddRdbColum(NativeRdb::RdbStore & store,const std::string & columName,const std::string & type)464 void ReminderStore::AddRdbColum(NativeRdb::RdbStore &store, const std::string &columName, const std::string &type)
465 {
466 std::string sqlStr = "";
467 if (type == "TEXT") {
468 sqlStr = "ALTER TABLE " + REMINDER_DB_TABLE + " ADD " + columName + " " + type + " DEFAULT '';";
469 } else if (type == "INT") {
470 //3 is meaning others
471 sqlStr = "ALTER TABLE " + REMINDER_DB_TABLE + " ADD " + columName + " " + type + " DEFAULT 3;";
472 }
473 ANSR_LOGD("AddRdbColum sqlStr = %{public}s", sqlStr.c_str());
474 int errorCode = store.ExecuteSql(sqlStr);
475 if (errorCode != NativeRdb::E_OK) {
476 ANSR_LOGE("AddRdbColum error,errorCode is = %{public}d", errorCode);
477 };
478 }
479 } // namespace Notification
480 } // namespace OHOS
481