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