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