1  /*
2   * Copyright (c) 2022-2023 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 "distributed_notification_manager.h"
17  
18  #include <vector>
19  
20  #include "ans_inner_errors.h"
21  #include "ans_log_wrapper.h"
22  #include "ans_watchdog.h"
23  #include "hitrace_meter_adapter.h"
24  
25  namespace OHOS {
26  namespace Notification {
27  namespace {
28  const std::string DELIMITER = "|";
29  }  // namespace
30  
DistributedNotificationManager()31  DistributedNotificationManager::DistributedNotificationManager()
32  {
33      ANS_LOGI("constructor");
34      distributedQueue_ = std::make_shared<ffrt::queue>("NotificationDistributedMgr");
35  
36      DistributedDatabaseCallback::IDatabaseChange databaseCallback = {
37          .OnInsert = std::bind(&DistributedNotificationManager::OnDatabaseInsert,
38              this,
39              std::placeholders::_1,
40              std::placeholders::_2,
41              std::placeholders::_3),
42          .OnUpdate = std::bind(&DistributedNotificationManager::OnDatabaseUpdate,
43              this,
44              std::placeholders::_1,
45              std::placeholders::_2,
46              std::placeholders::_3),
47          .OnDelete = std::bind(&DistributedNotificationManager::OnDatabaseDelete,
48              this,
49              std::placeholders::_1,
50              std::placeholders::_2,
51              std::placeholders::_3),
52      };
53      databaseCb_ = std::make_shared<DistributedDatabaseCallback>(databaseCallback);
54  
55      DistributedDeviceCallback::IDeviceChange deviceCallback = {
56          .OnConnected = std::bind(&DistributedNotificationManager::OnDeviceConnected, this, std::placeholders::_1),
57          .OnDisconnected = std::bind(&DistributedNotificationManager::OnDeviceDisconnected, this, std::placeholders::_1),
58      };
59      deviceCb_ = std::make_shared<DistributedDeviceCallback>(deviceCallback);
60      database_ = std::make_shared<DistributedDatabase>(databaseCb_, deviceCb_);
61  }
62  
~DistributedNotificationManager()63  DistributedNotificationManager::~DistributedNotificationManager()
64  {
65      ANS_LOGI("deconstructor");
66      if (distributedQueue_ != nullptr) {
67          ffrt::task_handle handler = distributedQueue_->submit_h(std::bind([&]() { callback_ = {}; }));
68          distributedQueue_->wait(handler);
69      }
70  }
71  
ResetFfrtQueue()72  void DistributedNotificationManager::ResetFfrtQueue()
73  {
74      if (distributedQueue_ != nullptr) {
75          distributedQueue_.reset();
76      }
77  }
78  
GenerateDistributedKey(const std::string & deviceId,const std::string & bundleName,const std::string & label,int32_t id,std::string & key)79  void DistributedNotificationManager::GenerateDistributedKey(
80      const std::string &deviceId, const std::string &bundleName, const std::string &label, int32_t id, std::string &key)
81  {
82      key = deviceId + DELIMITER + bundleName + DELIMITER + label + DELIMITER + ToString(id);
83  }
84  
GenerateLocalDistributedKey(const std::string & bundleName,const std::string & label,int32_t id,std::string & key)85  bool DistributedNotificationManager::GenerateLocalDistributedKey(
86      const std::string &bundleName, const std::string &label, int32_t id, std::string &key)
87  {
88      std::string deviceId;
89      if (database_ == nullptr) {
90          ANS_LOGE("database_ is invalid.");
91          return false;
92      }
93      if (!database_->GetLocalDeviceId(deviceId)) {
94          return false;
95      }
96  
97      GenerateDistributedKey(deviceId, bundleName, label, id, key);
98      return true;
99  }
100  
ResolveDistributedKey(const std::string & key,ResolveKey & resolveKey)101  bool DistributedNotificationManager::ResolveDistributedKey(const std::string &key, ResolveKey &resolveKey)
102  {
103      std::size_t deviceIdPosition = 0;
104      std::size_t deviceIdEndPosition = key.find(DELIMITER, deviceIdPosition);
105      if (deviceIdEndPosition == std::string::npos) {
106          return false;
107      }
108      std::size_t bundleNamePosition = deviceIdEndPosition + DELIMITER.size();
109      std::size_t bundleNameEndPosition = key.find(DELIMITER, bundleNamePosition);
110      if (bundleNameEndPosition == std::string::npos) {
111          return false;
112      }
113      std::size_t labelPosition = bundleNameEndPosition + DELIMITER.size();
114      std::size_t labelEndPosition = key.find_last_of(DELIMITER) - DELIMITER.size() + 1;
115      if (labelEndPosition < labelPosition) {
116          return false;
117      }
118      std::size_t idPosition = key.find_last_of(DELIMITER) + DELIMITER.size();
119  
120      resolveKey.deviceId = key.substr(deviceIdPosition, deviceIdEndPosition - deviceIdPosition);
121      resolveKey.bundleName = key.substr(bundleNamePosition, bundleNameEndPosition - bundleNamePosition);
122      resolveKey.label = key.substr(labelPosition, labelEndPosition - labelPosition);
123      resolveKey.id = atoi(&key[idPosition]);
124  
125      return true;
126  }
127  
CheckDeviceId(const std::string & deviceId,const std::string & key)128  bool DistributedNotificationManager::CheckDeviceId(const std::string &deviceId, const std::string &key)
129  {
130      ResolveKey resolveKey;
131      if (!ResolveDistributedKey(key, resolveKey)) {
132          ANS_LOGE("key <%{public}s> is invalid.", key.c_str());
133          return false;
134      }
135  
136      return deviceId == resolveKey.deviceId;
137  }
138  
OnDatabaseInsert(const std::string & deviceId,const std::string & key,const std::string & value)139  void DistributedNotificationManager::OnDatabaseInsert(
140      const std::string &deviceId, const std::string &key, const std::string &value)
141  {
142      ANS_LOGD("start");
143      if (distributedQueue_ == nullptr) {
144          ANS_LOGE("Serial queue is nullptr.");
145          return;
146      }
147      distributedQueue_->submit(std::bind([=]() {
148          if (!CheckDeviceId(deviceId, key)) {
149              ANS_LOGD("device id is distinct. deviceId:%{public}s key:%{public}s", deviceId.c_str(), key.c_str());
150          }
151  
152          ResolveKey resolveKey;
153          if (!ResolveDistributedKey(key, resolveKey)) {
154              ANS_LOGE("key <%{public}s> is invalidity.", key.c_str());
155              return;
156          }
157  
158          sptr<NotificationRequest> request =
159              NotificationJsonConverter::ConvertFromJsonString<NotificationRequest>(value);
160          if (request == nullptr) {
161              ANS_LOGE("convert json to request failed. key:%{public}s", key.c_str());
162              return;
163          }
164  
165          PublishCallback(resolveKey.deviceId, resolveKey.bundleName, request);
166      }));
167  }
168  
OnDatabaseUpdate(const std::string & deviceId,const std::string & key,const std::string & value)169  void DistributedNotificationManager::OnDatabaseUpdate(
170      const std::string &deviceId, const std::string &key, const std::string &value)
171  {
172      ANS_LOGD("start");
173      if (distributedQueue_ == nullptr) {
174          ANS_LOGE("Serial queue is invalid.");
175          return;
176      }
177      ffrt::task_handle handler = distributedQueue_->submit_h(std::bind([=]() {
178          if (!CheckDeviceId(deviceId, key)) {
179              ANS_LOGD("device id are not the same. deviceId:%{public}s key:%{public}s", deviceId.c_str(), key.c_str());
180          }
181  
182          ResolveKey resolveKey;
183          if (!ResolveDistributedKey(key, resolveKey)) {
184              ANS_LOGE("key <%{public}s> is invalid.", key.c_str());
185              return;
186          }
187  
188          sptr<NotificationRequest> request =
189              NotificationJsonConverter::ConvertFromJsonString<NotificationRequest>(value);
190          if (request == nullptr) {
191              ANS_LOGE("convert json to request failed. key:%{public}s", key.c_str());
192              return;
193          }
194  
195          UpdateCallback(resolveKey.deviceId, resolveKey.bundleName, request);
196      }));
197  }
198  
OnDatabaseDelete(const std::string & deviceId,const std::string & key,const std::string & value)199  void DistributedNotificationManager::OnDatabaseDelete(
200      const std::string &deviceId, const std::string &key, const std::string &value)
201  {
202      ANS_LOGD("start");
203      if (distributedQueue_ == nullptr) {
204          ANS_LOGE("Serial queue is invalid.");
205          return;
206      }
207      distributedQueue_->submit(std::bind([=]() {
208          if (!CheckDeviceId(deviceId, key)) {
209              ANS_LOGD("device id are not the same. deviceId:%{public}s key:%{public}s", deviceId.c_str(), key.c_str());
210          }
211  
212          ResolveKey resolveKey;
213          if (!ResolveDistributedKey(key, resolveKey)) {
214              ANS_LOGE("key <%{public}s> is invalid.", key.c_str());
215              return;
216          }
217  
218          DeleteCallback(resolveKey.deviceId, resolveKey.bundleName, resolveKey.label, resolveKey.id);
219      }));
220  }
221  
OnDeviceConnected(const std::string & deviceId)222  void DistributedNotificationManager::OnDeviceConnected(const std::string &deviceId)
223  {
224      ANS_LOGD("start");
225      if (distributedQueue_ == nullptr) {
226          ANS_LOGE("Serial queue is invalid.");
227          return;
228      }
229      distributedQueue_->submit(std::bind([=]() {
230          if (database_ == nullptr) {
231              ANS_LOGE("OnDeviceConnected failed: database is null");
232              return;
233          }
234          if (!database_->OnDeviceConnected()) {
235              ANS_LOGE("OnDeviceConnected failed.");
236          }
237      }));
238  }
239  
OnDeviceDisconnected(const std::string & deviceId)240  void DistributedNotificationManager::OnDeviceDisconnected(const std::string &deviceId)
241  {
242      ANS_LOGD("start");
243      if (distributedQueue_ == nullptr) {
244          ANS_LOGE("Serial queue is invalid.");
245          return;
246      }
247      distributedQueue_->submit(std::bind([=]() {
248          std::string prefixKey = deviceId + DELIMITER;
249          std::vector<DistributedDatabase::Entry> entries;
250          if (database_ == nullptr) {
251              ANS_LOGE("database_ is invalid.");
252              return;
253          }
254          if (!database_->GetEntriesFromDistributedDB(prefixKey, entries)) {
255              ANS_LOGE("GetEntriesFromDistributedDB failed.");
256              return;
257          }
258  
259          for (auto index : entries) {
260              ResolveKey resolveKey;
261              if (!ResolveDistributedKey(index.key.ToString(), resolveKey)) {
262                  ANS_LOGE("key <%{public}s> is invalid.", index.key.ToString().c_str());
263                  continue;
264              }
265  
266              DeleteCallback(resolveKey.deviceId, resolveKey.bundleName, resolveKey.label, resolveKey.id);
267          }
268  
269          database_->ClearDataByDevice(deviceId);
270  
271          std::vector<DistributedDatabase::DeviceInfo> deviceList;
272          if (database_->GetDeviceInfoList(deviceList) == ERR_OK && deviceList.empty()) {
273              database_->RecreateDistributedDB();
274          }
275      }));
276  }
277  
PublishCallback(const std::string & deviceId,const std::string & bundleName,sptr<NotificationRequest> & request)278  bool DistributedNotificationManager::PublishCallback(
279      const std::string &deviceId, const std::string &bundleName, sptr<NotificationRequest> &request)
280  {
281      ANS_LOGI("start");
282      if (callback_.OnPublish) {
283          callback_.OnPublish(deviceId, bundleName, request);
284      }
285      ANS_LOGD("end");
286  
287      return true;
288  }
289  
UpdateCallback(const std::string & deviceId,const std::string & bundleName,sptr<NotificationRequest> & request)290  bool DistributedNotificationManager::UpdateCallback(
291      const std::string &deviceId, const std::string &bundleName, sptr<NotificationRequest> &request)
292  {
293      ANS_LOGI("start");
294      if (callback_.OnUpdate) {
295          callback_.OnUpdate(deviceId, bundleName, request);
296      }
297      ANS_LOGD("end");
298  
299      return true;
300  }
301  
DeleteCallback(const std::string & deviceId,const std::string & bundleName,const std::string & label,int32_t id)302  bool DistributedNotificationManager::DeleteCallback(
303      const std::string &deviceId, const std::string &bundleName, const std::string &label, int32_t id)
304  {
305      ANS_LOGI("start");
306      if (callback_.OnDelete) {
307          callback_.OnDelete(deviceId, bundleName, label, id);
308      }
309      ANS_LOGD("end");
310  
311      return true;
312  }
313  
Publish(const std::string & bundleName,const std::string & label,int32_t id,const sptr<NotificationRequest> & request)314  ErrCode DistributedNotificationManager::Publish(
315      const std::string &bundleName, const std::string &label, int32_t id, const sptr<NotificationRequest> &request)
316  {
317      HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__);
318      ANS_LOGD("start");
319      std::string key;
320      if (!GenerateLocalDistributedKey(bundleName, label, id, key)) {
321          ANS_LOGE("Failed to generate distributed key.");
322          return ERR_ANS_DISTRIBUTED_GET_INFO_FAILED;
323      }
324  
325      std::string value;
326      if (!NotificationJsonConverter::ConvertToJsonString(request, value)) {
327          ANS_LOGE("convert request to json failed. key:%{public}s", key.c_str());
328          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
329      }
330  
331      if (database_ == nullptr) {
332          ANS_LOGE("database_ is nullptr.");
333          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
334      }
335      if (!database_->PutToDistributedDB(key, value)) {
336          ANS_LOGE("put to distributed DB failed. key:%{public}s", key.c_str());
337          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
338      }
339  
340      return ERR_OK;
341  }
342  
Update(const std::string & bundleName,const std::string & label,int32_t id,const sptr<NotificationRequest> & request)343  ErrCode DistributedNotificationManager::Update(
344      const std::string &bundleName, const std::string &label, int32_t id, const sptr<NotificationRequest> &request)
345  {
346      ANS_LOGD("start");
347      std::string key;
348      if (!GenerateLocalDistributedKey(bundleName, label, id, key)) {
349          ANS_LOGE("Generate distributed key failed.");
350          return ERR_ANS_DISTRIBUTED_GET_INFO_FAILED;
351      }
352  
353      std::string value;
354      if (!NotificationJsonConverter::ConvertToJsonString(request, value)) {
355          ANS_LOGE("convert request to json failed. key:%{public}s", key.c_str());
356          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
357      }
358  
359      if (database_ == nullptr) {
360          ANS_LOGE("database_ is invalid.");
361          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
362      }
363      if (!database_->PutToDistributedDB(key, value)) {
364          ANS_LOGE("put to distributed DB failed. key:%{public}s", key.c_str());
365          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
366      }
367      return ERR_OK;
368  }
369  
Delete(const std::string & bundleName,const std::string & label,int32_t id)370  ErrCode DistributedNotificationManager::Delete(const std::string &bundleName, const std::string &label, int32_t id)
371  {
372      HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__);
373      ANS_LOGD("start");
374      std::string key;
375      if (!GenerateLocalDistributedKey(bundleName, label, id, key)) {
376          ANS_LOGE("Generate distributed key failed.");
377          return ERR_ANS_DISTRIBUTED_GET_INFO_FAILED;
378      }
379  
380      if (database_ == nullptr) {
381          ANS_LOGE("database_ is nullptr.");
382          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
383      }
384      if (!database_->DeleteToDistributedDB(key)) {
385          ANS_LOGE("Failed to DeleteToDistributedDB. key:%{public}s", key.c_str());
386          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
387      }
388      return ERR_OK;
389  }
390  
DeleteRemoteNotification(const std::string & deviceId,const std::string & bundleName,const std::string & label,int32_t id)391  ErrCode DistributedNotificationManager::DeleteRemoteNotification(
392      const std::string &deviceId, const std::string &bundleName, const std::string &label, int32_t id)
393  {
394      HITRACE_METER_NAME(HITRACE_TAG_NOTIFICATION, __PRETTY_FUNCTION__);
395      ANS_LOGD("start");
396  
397      std::string key;
398      GenerateDistributedKey(deviceId, bundleName, label, id, key);
399  
400      if (database_ == nullptr) {
401          ANS_LOGE("database_ is invalid.");
402          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
403      }
404      if (!database_->DeleteToDistributedDB(key)) {
405          ANS_LOGE("delete to distributed DB failed. key:%{public}s", key.c_str());
406          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
407      }
408      return ERR_OK;
409  }
410  
RegisterCallback(const IDistributedCallback & callback)411  ErrCode DistributedNotificationManager::RegisterCallback(const IDistributedCallback &callback)
412  {
413      ANS_LOGD("start");
414      if (distributedQueue_ == nullptr) {
415          ANS_LOGE("Serial queue is invalid.");
416          return ERR_ANS_INVALID_PARAM;
417      }
418      ffrt::task_handle handler = distributedQueue_->submit_h(std::bind([&]() { callback_ = callback; }));
419      distributedQueue_->wait(handler);
420      return ERR_OK;
421  }
422  
UngegisterCallback()423  ErrCode DistributedNotificationManager::UngegisterCallback()
424  {
425      ANS_LOGD("start");
426      if (distributedQueue_ == nullptr) {
427          ANS_LOGE("Serial queue is invalid.");
428          return ERR_ANS_INVALID_PARAM;
429      }
430      ffrt::task_handle handler = distributedQueue_->submit_h(std::bind([&]() { callback_ = {}; }));
431      distributedQueue_->wait(handler);
432      return ERR_OK;
433  }
434  
GetCurrentDistributedNotification(std::vector<sptr<NotificationRequest>> & requestList)435  ErrCode DistributedNotificationManager::GetCurrentDistributedNotification(
436      std::vector<sptr<NotificationRequest>> &requestList)
437  {
438      ANS_LOGD("start");
439      std::string prefixKey = "";
440      std::vector<DistributedDatabase::Entry> entries;
441      if (database_ == nullptr) {
442          ANS_LOGE("database_ is invalid.");
443          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
444      }
445      if (!database_->GetEntriesFromDistributedDB(prefixKey, entries)) {
446          ANS_LOGE("GetEntriesFromDistributedDB failed.");
447          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
448      }
449  
450      for (auto index : entries) {
451          ResolveKey resolveKey;
452          if (!ResolveDistributedKey(index.key.ToString(), resolveKey)) {
453              ANS_LOGE("key <%{public}s> is invalid.", index.key.ToString().c_str());
454              continue;
455          }
456  
457          sptr<NotificationRequest> request =
458              NotificationJsonConverter::ConvertFromJsonString<NotificationRequest>(index.value.ToString());
459          if (request == nullptr) {
460              ANS_LOGE("convert json to request failed. key:%{public}s", index.key.ToString().c_str());
461              continue;
462          }
463  
464          PublishCallback(resolveKey.deviceId, resolveKey.bundleName, request);
465      }
466  
467      return ERR_OK;
468  }
469  
GetLocalDeviceInfo(DistributedDatabase::DeviceInfo & deviceInfo)470  ErrCode DistributedNotificationManager::GetLocalDeviceInfo(DistributedDatabase::DeviceInfo &deviceInfo)
471  {
472      ANS_LOGD("start");
473      if (database_ == nullptr) {
474          ANS_LOGE("database_ is invalid.");
475          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
476      }
477      if (!database_->GetLocalDeviceInfo(deviceInfo)) {
478          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
479      }
480  
481      return ERR_OK;
482  }
483  
OnDistributedKvStoreDeathRecipient()484  ErrCode DistributedNotificationManager::OnDistributedKvStoreDeathRecipient()
485  {
486      ANS_LOGD("start");
487      database_ = std::make_shared<DistributedDatabase>(databaseCb_, deviceCb_);
488      if (!database_->RecreateDistributedDB()) {
489          ANS_LOGE("RecreateDistributedDB failed.");
490          return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
491      }
492      return ERR_OK;
493  }
494  }  // namespace Notification
495  }  // namespace OHOS