• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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_extension_service.h"
17 
18 #include "ans_log_wrapper.h"
19 #include "event_report.h"
20 #include "notification_analytics_util.h"
21 
22 #include <utility>
23 
24 namespace OHOS {
25 namespace Notification {
26 
27 using namespace DistributedHardware;
28 
29 using DeviceCallback = std::function<bool(std::string, int32_t, bool)>;
30 typedef int32_t (*INIT_LOCAL_DEVICE)(const std::string &deviceId, uint16_t deviceType,
31     DistributedDeviceConfig config);
32 typedef void (*RELEASE_LOCAL_DEVICE)();
33 typedef void (*ADD_DEVICE)(const std::string &deviceId, uint16_t deviceType,
34     const std::string &networkId);
35 typedef void (*RELEASE_DEVICE)(const std::string &deviceId, uint16_t deviceType);
36 typedef void (*REFRESH_DEVICE)(const std::string &deviceId, uint16_t deviceType,
37     const std::string &networkId);
38 typedef void (*INIT_HA_CALLBACK)(
39     std::function<void(int32_t, int32_t, uint32_t, std::string)> callback);
40 typedef void (*INIT_SENDREPORT_CALLBACK)(
41     std::function<void(int32_t, int32_t, std::string)> callback);
42 
43 namespace {
44 constexpr int32_t DEFAULT_TITLE_LENGTH = 200;
45 constexpr int32_t DEFAULT_CONTENT_LENGTH = 400;
46 constexpr uint64_t IDEL_TASK_DELAY = 30 * 1000 * 1000;
47 constexpr char const APP_ID[] = "com.ohos.notification_service.3203";
48 constexpr const char* CFG_KEY_DISTRIBUTED = "distribuedConfig";
49 constexpr const char* CFG_KEY_LOCAL_TYPE = "localType";
50 constexpr const char* CFG_KEY_SUPPORT_DEVICES = "supportPeerDevice";
51 constexpr const char* CFG_KEY_TITLE_LENGTH = "maxTitleLength";
52 constexpr const char* CFG_KEY_CONTENT_LENGTH = "maxContentLength";
53 constexpr const char* CFG_KEY_REPLY_TIMEOUT = "operationReplyTimeout";
54 constexpr const int32_t PUBLISH_ERROR_EVENT_CODE = 0;
55 constexpr const int32_t DELETE_ERROR_EVENT_CODE = 5;
56 constexpr const int32_t MODIFY_ERROR_EVENT_CODE = 6;
57 constexpr const int32_t ANS_CUSTOMIZE_CODE = 7;
58 
59 static const int32_t MAX_DATA_LENGTH = 7;
60 static const int32_t START_ANONYMOUS_INDEX = 5;
61 constexpr int64_t DURATION_ONE_SECOND = 1000;  // 1s, millisecond
62 }
63 
TransDeviceTypeToName(uint16_t deviceType_)64 std::string TransDeviceTypeToName(uint16_t deviceType_)
65 {
66     switch (deviceType_) {
67         case DmDeviceType::DEVICE_TYPE_WATCH: {
68             return "Watch";
69         }
70         case DmDeviceType::DEVICE_TYPE_PAD: {
71             return "Pad";
72         }
73         case DmDeviceType::DEVICE_TYPE_PHONE: {
74             return "Phone";
75         }
76         default:
77             return "";
78     }
79 }
80 
GetInstance()81 DistributedExtensionService& DistributedExtensionService::GetInstance()
82 {
83     static DistributedExtensionService distributedExtensionService;
84     return distributedExtensionService;
85 }
86 
DistributedExtensionService()87 DistributedExtensionService::DistributedExtensionService()
88 {
89     if (!initConfig()) {
90         return;
91     }
92     distributedQueue_ = std::make_shared<ffrt::queue>("ans_extension");
93     if (distributedQueue_ == nullptr) {
94         ANS_LOGW("ffrt create failed!");
95         return;
96     }
97 }
98 
~DistributedExtensionService()99 DistributedExtensionService::~DistributedExtensionService()
100 {
101     std::function<void()> task = std::bind([&]() {
102         ReleaseLocalDevice();
103         dansHandler_.reset();
104         dansRunning_.store(false);
105     });
106     ANS_LOGI("Dans release.");
107     ffrt::task_handle handler = distributedQueue_->submit_h(task);
108     distributedQueue_->wait(handler);
109 }
110 
initConfig()111 bool DistributedExtensionService::initConfig()
112 {
113     nlohmann::json root;
114     std::string jsonPoint = "/";
115     jsonPoint.append(NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE);
116     jsonPoint.append("/");
117     jsonPoint.append(CFG_KEY_DISTRIBUTED);
118     if (!NotificationConfigParse::GetInstance()->GetConfigJson(jsonPoint, root)) {
119         return false;
120     }
121 
122     if (root.find(NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE) == root.end()) {
123         ANS_LOGE("Dans initConfig failed as can not find notificationService.");
124         return false;
125     }
126 
127     nlohmann::json configJson = root[NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE][CFG_KEY_DISTRIBUTED];
128     if (configJson.is_null() || configJson.empty()) {
129         ANS_LOGE("Dans initConfig failed as invalid json.");
130         return false;
131     }
132 
133     nlohmann::json localTypeJson = configJson[CFG_KEY_LOCAL_TYPE];
134     if (localTypeJson.is_null() || localTypeJson.empty()) {
135         ANS_LOGE("Dans initConfig local type as invalid json.");
136     } else {
137         deviceConfig_.localType = localTypeJson.get<std::string>();
138         ANS_LOGI("Dans initConfig local type %{public}s.", deviceConfig_.localType.c_str());
139     }
140 
141     nlohmann::json supportJson = configJson[CFG_KEY_SUPPORT_DEVICES];
142     if (supportJson.is_null() || supportJson.empty() || !supportJson.is_array()) {
143         ANS_LOGE("Dans initConfig support type as invalid json.");
144         return false;
145     }
146 
147     for (auto &deviceJson : supportJson) {
148         ANS_LOGI("Dans initConfig support type %{public}s.", deviceJson.get<std::string>().c_str());
149         deviceConfig_.supportPeerDevice.insert(deviceJson.get<std::string>());
150     }
151 
152     nlohmann::json titleJson = configJson[CFG_KEY_TITLE_LENGTH];
153     if (titleJson.is_null() || titleJson.empty() || !titleJson.is_number_integer()) {
154         deviceConfig_.maxTitleLength = DEFAULT_TITLE_LENGTH;
155     } else {
156         deviceConfig_.maxTitleLength = titleJson.get<int32_t>();
157         ANS_LOGI("Dans initConfig title length %{public}d.", deviceConfig_.maxTitleLength);
158     }
159 
160     SetMaxContentLength(configJson);
161     SetOperationReplyTimeout(configJson);
162 
163     deviceConfig_.collaborativeDeleteTypes = NotificationConfigParse::GetInstance()->GetCollaborativeDeleteType();
164     deviceConfig_.startAbilityTimeout = NotificationConfigParse::GetInstance()->GetStartAbilityTimeout();
165     return true;
166 }
167 
InitDans()168 int32_t DistributedExtensionService::InitDans()
169 {
170     if (dansRunning_.load() && dansHandler_ != nullptr && dansHandler_->IsValid()) {
171         return 0;
172     }
173     dansHandler_ = std::make_shared<NotificationLoadUtils>("libdans.z.so");
174     if (dansHandler_ == nullptr) {
175         ANS_LOGW("Dans handler init failed.");
176         return -1;
177     }
178 
179     INIT_LOCAL_DEVICE handler = (INIT_LOCAL_DEVICE)dansHandler_->GetProxyFunc("InitLocalDevice");
180     if (handler == nullptr) {
181         ANS_LOGW("Dans init failed.");
182         return -1;
183     }
184 
185     DmDeviceInfo deviceInfo;
186     int32_t result = DeviceManager::GetInstance().GetLocalDeviceInfo(APP_ID, deviceInfo);
187     if (result != 0) {
188         ANS_LOGW("Dans get local device failed.");
189         return -1;
190     }
191 
192     ANS_LOGI("Dans get local device %{public}s, %{public}d, %{public}d, %{public}d.",
193         StringAnonymous(deviceInfo.deviceId).c_str(), deviceInfo.deviceTypeId,
194         deviceConfig_.maxTitleLength, deviceConfig_.maxContentLength);
195     if (handler(deviceInfo.deviceId, deviceInfo.deviceTypeId, deviceConfig_) != 0) {
196         dansRunning_.store(false);
197         return -1;
198     }
199 
200     INIT_HA_CALLBACK haHandler = (INIT_HA_CALLBACK)dansHandler_->GetProxyFunc("InitHACallBack");
201     if (haHandler != nullptr) {
202         haHandler(std::bind(&DistributedExtensionService::HADotCallback, this, std::placeholders::_1,
203         std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
204     }
205 
206     INIT_SENDREPORT_CALLBACK sendHandler =
207         (INIT_SENDREPORT_CALLBACK)dansHandler_->GetProxyFunc("InitSendReportCallBack");
208     if (sendHandler != nullptr) {
209         sendHandler(std::bind(&DistributedExtensionService::SendReportCallback, this, std::placeholders::_1,
210         std::placeholders::_2, std::placeholders::_3));
211     }
212 
213     dansRunning_.store(true);
214     return 0;
215 }
216 
ReleaseLocalDevice()217 int32_t DistributedExtensionService::ReleaseLocalDevice()
218 {
219     if (!dansRunning_.load() || dansHandler_ == nullptr || !dansHandler_->IsValid()) {
220         return 0;
221     }
222 
223     RELEASE_LOCAL_DEVICE handler = (RELEASE_LOCAL_DEVICE)dansHandler_->GetProxyFunc("ReleaseLocalDevice");
224     if (handler == nullptr) {
225         ANS_LOGW("Dans release failed, handler is null.");
226         return -1;
227     }
228     handler();
229     ANS_LOGI("Dans release successfully.");
230     return 0;
231 }
232 
OnDeviceOnline(const DmDeviceInfo & deviceInfo)233 void DistributedExtensionService::OnDeviceOnline(const DmDeviceInfo &deviceInfo)
234 {
235     std::string name = TransDeviceTypeToName(deviceInfo.deviceTypeId);
236     if (deviceConfig_.supportPeerDevice.find(name) == deviceConfig_.supportPeerDevice.end()) {
237         ANS_LOGI("The current device type not support %{public}d.", deviceInfo.deviceTypeId);
238         return;
239     }
240     if (distributedQueue_ == nullptr) {
241         return;
242     }
243     std::function<void()> onlineTask = std::bind([&, deviceInfo]() {
244         if (InitDans() != 0) {
245             ANS_LOGW("OnDeviceOnline init dans failed.");
246             return;
247         };
248 
249         ADD_DEVICE handler = (ADD_DEVICE)dansHandler_->GetProxyFunc("AddDevice");
250         if (handler == nullptr) {
251             ANS_LOGW("Dans handler is null ptr.");
252             return;
253         }
254         std::lock_guard<std::mutex> lock(mapLock_);
255         handler(deviceInfo.deviceId, deviceInfo.deviceTypeId, deviceInfo.networkId);
256         std::string reason = "deviceType: " + std::to_string(deviceInfo.deviceTypeId) +
257             " ; deviceId: " + AnonymousProcessing(deviceInfo.deviceId) + " ; networkId: " +
258             AnonymousProcessing(deviceInfo.networkId);
259         HADotCallback(PUBLISH_ERROR_EVENT_CODE, 0, EventSceneId::SCENE_1, reason);
260         DistributedDeviceInfo device = DistributedDeviceInfo(deviceInfo.deviceId, deviceInfo.deviceName,
261             deviceInfo.networkId, deviceInfo.deviceTypeId);
262         deviceMap_.insert(std::make_pair(deviceInfo.deviceId, device));
263     });
264     distributedQueue_->submit(onlineTask);
265 }
266 
HADotCallback(int32_t code,int32_t ErrCode,uint32_t branchId,std::string reason)267 void DistributedExtensionService::HADotCallback(int32_t code, int32_t ErrCode, uint32_t branchId, std::string reason)
268 {
269     ANS_LOGI("Dans ha callback %{public}d, %{public}d, %{public}s.", code, ErrCode, reason.c_str());
270     if (code == PUBLISH_ERROR_EVENT_CODE) {
271         if (reason.find("deviceType") != std::string::npos ||
272             reason.find("ShutdownReason") != std::string::npos) {
273             HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_21, branchId).Message(reason);
274             NotificationAnalyticsUtil::ReportPublishFailedEvent(message);
275         } else {
276             HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_20, branchId)
277                                         .ErrorCode(ErrCode)
278                                         .Message(reason);
279             NotificationAnalyticsUtil::ReportPublishFailedEvent(message);
280         }
281     } else if (code == DELETE_ERROR_EVENT_CODE) {
282         HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_20, branchId)
283                                     .DeleteReason(NotificationConstant::DISTRIBUTED_COLLABORATIVE_DELETE)
284                                     .ErrorCode(ErrCode)
285                                     .Message(reason);
286         NotificationAnalyticsUtil::ReportDeleteFailedEvent(message);
287     } else if (code == ANS_CUSTOMIZE_CODE) {
288         if (branchId == BRANCH_3) {
289             HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_1, branchId)
290                                         .ClickByWatch()
291                                         .SlotType(ErrCode);
292             NotificationAnalyticsUtil::ReportOperationsDotEvent(message);
293         } else if (branchId == BRANCH_4) {
294             HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_1, branchId)
295                                         .ReplyByWatch()
296                                         .SlotType(ErrCode);
297             NotificationAnalyticsUtil::ReportOperationsDotEvent(message);
298         } else {
299             bool isLiveView = false;
300             if (ErrCode == NotificationConstant::SlotType::LIVE_VIEW) {
301                 isLiveView = true;
302             }
303             HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_1, branchId)
304                                         .DelByWatch(isLiveView)
305                                         .SlotType(ErrCode);
306             NotificationAnalyticsUtil::ReportOperationsDotEvent(message);
307         }
308     } else if (code == MODIFY_ERROR_EVENT_CODE) {
309         HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_20, branchId)
310                                     .ErrorCode(ErrCode)
311                                     .Message(reason);
312         NotificationAnalyticsUtil::ReportSkipFailedEvent(message);
313     }
314 }
315 
SendReportCallback(int32_t messageType,int32_t errCode,std::string reason)316 void DistributedExtensionService::SendReportCallback(
317     int32_t messageType, int32_t errCode, std::string reason)
318 {
319     EventInfo eventInfo;
320     eventInfo.messageType = messageType;
321     eventInfo.errCode = errCode;
322     eventInfo.reason = reason;
323     EventReport::SendHiSysEvent(EVENT_NOTIFICATION_ERROR, eventInfo);
324 }
325 
OnDeviceOffline(const DmDeviceInfo & deviceInfo)326 void DistributedExtensionService::OnDeviceOffline(const DmDeviceInfo &deviceInfo)
327 {
328     if (distributedQueue_ == nullptr) {
329         return;
330     }
331     std::function<void()> offlineTask = std::bind([&, deviceInfo]() {
332         std::lock_guard<std::mutex> lock(mapLock_);
333         if (deviceMap_.count(deviceInfo.deviceId) == 0) {
334             ANS_LOGI("Not target device %{public}s", StringAnonymous(deviceInfo.deviceId).c_str());
335             return;
336         }
337         if (!dansRunning_.load() || dansHandler_ == nullptr || !dansHandler_->IsValid()) {
338             ANS_LOGW("Dans state not normal %{public}d", dansRunning_.load());
339             return;
340         }
341         RELEASE_DEVICE handler = (RELEASE_DEVICE)dansHandler_->GetProxyFunc("ReleaseDevice");
342         if (handler == nullptr) {
343             ANS_LOGW("Dans handler is null ptr.");
344             return;
345         }
346         handler(deviceInfo.deviceId, deviceInfo.deviceTypeId);
347         std::string reason = "deviceType: " + std::to_string(deviceInfo.deviceTypeId) +
348                              " ; deviceId: " + AnonymousProcessing(deviceInfo.deviceId);
349         HADotCallback(PUBLISH_ERROR_EVENT_CODE, 0, EventSceneId::SCENE_2, reason);
350         deviceMap_.erase(deviceInfo.deviceId);
351     });
352     distributedQueue_->submit(offlineTask);
353 }
354 
OnDeviceChanged(const DmDeviceInfo & deviceInfo)355 void DistributedExtensionService::OnDeviceChanged(const DmDeviceInfo &deviceInfo)
356 {
357     if (distributedQueue_ == nullptr) {
358         return;
359     }
360     std::function<void()> changeTask = std::bind([&, deviceInfo]() {
361         std::lock_guard<std::mutex> lock(mapLock_);
362         if (deviceMap_.count(deviceInfo.deviceId) == 0) {
363             ANS_LOGI("Not target device %{public}s", StringAnonymous(deviceInfo.deviceId).c_str());
364             return;
365         }
366         if (!dansRunning_.load() || dansHandler_ == nullptr || !dansHandler_->IsValid()) {
367             ANS_LOGW("Dans state not normal %{public}d", dansRunning_.load());
368             return;
369         }
370         REFRESH_DEVICE handler = (REFRESH_DEVICE)dansHandler_->GetProxyFunc("RefreshDevice");
371         if (handler == nullptr) {
372             ANS_LOGW("Dans handler is null ptr.");
373             return;
374         }
375         handler(deviceInfo.deviceId, deviceInfo.deviceTypeId, deviceInfo.networkId);
376         ANS_LOGI("Dans refresh %{public}s %{public}s.", StringAnonymous(deviceInfo.deviceId).c_str(),
377             StringAnonymous(deviceInfo.networkId).c_str());
378     });
379     distributedQueue_->submit(changeTask);
380 }
381 
GetOperationReplyTimeout()382 int32_t DistributedExtensionService::GetOperationReplyTimeout()
383 {
384     return deviceConfig_.operationReplyTimeout * DURATION_ONE_SECOND;
385 }
386 
SetOperationReplyTimeout(nlohmann::json & configJson)387 void DistributedExtensionService::SetOperationReplyTimeout(nlohmann::json &configJson)
388 {
389     nlohmann::json contentJson = configJson[CFG_KEY_REPLY_TIMEOUT];
390     if (contentJson.is_null() || contentJson.empty() || !contentJson.is_number_integer()) {
391         deviceConfig_.operationReplyTimeout = DEFAULT_REPLY_TIMEOUT;
392     } else {
393         deviceConfig_.operationReplyTimeout = contentJson.get<int32_t>();
394         ANS_LOGI("Dans initConfig reply timeout %{public}d.", deviceConfig_.operationReplyTimeout);
395     }
396 }
397 
SetMaxContentLength(nlohmann::json & configJson)398 void DistributedExtensionService::SetMaxContentLength(nlohmann::json &configJson)
399 {
400     nlohmann::json contentJson = configJson[CFG_KEY_CONTENT_LENGTH];
401     if (contentJson.is_null() || contentJson.empty() || !contentJson.is_number_integer()) {
402         deviceConfig_.maxContentLength = DEFAULT_CONTENT_LENGTH;
403     } else {
404         deviceConfig_.maxContentLength = contentJson.get<int32_t>();
405         ANS_LOGI("Dans initConfig content length %{public}d.", deviceConfig_.maxContentLength);
406     }
407 }
408 
AnonymousProcessing(std::string data)409 std::string DistributedExtensionService::AnonymousProcessing(std::string data)
410 {
411     int32_t length = data.length();
412     if (length >= MAX_DATA_LENGTH) {
413         data.replace(START_ANONYMOUS_INDEX, length - 1, "**");
414     }
415     return data;
416 }
417 }
418 }
419