1 /*
2 * Copyright (c) 2025 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 "advanced_notification_service.h"
17
18 #include "accesstoken_kit.h"
19 #include "access_token_helper.h"
20 #include "advanced_notification_flow_control_service.h"
21 #include "advanced_notification_inline.h"
22 #include "ans_const_define.h"
23 #include "ans_inner_errors.h"
24 #include "ans_log_wrapper.h"
25 #include "ans_trace_wrapper.h"
26 #include "ans_status.h"
27
28 #include "notification_analytics_util.h"
29 #include "os_account_manager.h"
30 #include "os_account_manager_helper.h"
31 #include "string_wrapper.h"
32 #include "hitrace_util.h"
33
34 namespace OHOS {
35 namespace Notification {
36
37 constexpr char FOUNDATION_BUNDLE_NAME[] = "ohos.global.systemres";
38 constexpr int32_t RESSCHED_UID = 1096;
39 constexpr int32_t OPERATION_TYPE_COMMON_EVENT = 4;
40 constexpr int32_t TYPE_CODE_DOWNLOAD = 8;
41
PublishWithMaxCapacity(const std::string & label,const sptr<NotificationRequest> & request)42 ErrCode AdvancedNotificationService::PublishWithMaxCapacity(
43 const std::string& label, const sptr<NotificationRequest>& request)
44 {
45 return Publish(label, request);
46 }
47
Publish(const std::string & label,const sptr<NotificationRequest> & request)48 ErrCode AdvancedNotificationService::Publish(const std::string &label, const sptr<NotificationRequest> &request)
49 {
50 NOTIFICATION_HITRACE(HITRACE_TAG_NOTIFICATION);
51 TraceChainUtil traceChain = TraceChainUtil();
52 OHOS::HiviewDFX::HiTraceId traceId = OHOS::HiviewDFX::HiTraceChain::GetId();
53 ANS_LOGD("called");
54
55 auto fullTokenID = IPCSkeleton::GetCallingFullTokenID();
56 if (Security::AccessToken::AccessTokenKit::IsAtomicServiceByFullTokenID(fullTokenID)) {
57 ANS_LOGE("AtomicService is not allowed to publish notification");
58 return ERR_ANS_PERMISSION_DENIED;
59 }
60
61 const auto checkResult = CheckNotificationRequest(request);
62 if (checkResult != ERR_OK) {
63 return checkResult;
64 }
65
66 SetChainIdToExtraInfo(request, traceId);
67 if (request->GetDistributedCollaborate()) {
68 return CollaboratePublish(request);
69 }
70
71 if (request->IsAtomicServiceNotification()) {
72 return AtomicServicePublish(request);
73 }
74
75 if (!InitPublishProcess()) {
76 return ERR_ANS_NO_MEMORY;
77 }
78
79 request->SetCreateTime(GetCurrentTime());
80
81 bool isUpdateByOwnerAllowed = IsUpdateSystemLiveviewByOwner(request);
82 AnsStatus ansStatus = publishProcess_[request->GetSlotType()]->PublishPreWork(request, isUpdateByOwnerAllowed);
83 if (!ansStatus.Ok()) {
84 ansStatus.AppendSceneBranch(EventSceneId::SCENE_1, EventBranchId::BRANCH_0, "publish prework failed");
85 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, ansStatus.BuildMessage(true));
86 return ansStatus.GetErrCode();
87 }
88
89 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_1, EventBranchId::BRANCH_1);
90 ErrCode result = CheckUserIdParams(request->GetReceiverUserId());
91 if (result != ERR_OK) {
92 message.SceneId(EventSceneId::SCENE_3).ErrorCode(result).Message("User is invalid", true);
93 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
94 return result;
95 }
96 bool isSubsystem = AccessTokenHelper::VerifyNativeToken(IPCSkeleton::GetCallingTokenID());
97 request->SetIsSystemApp(AccessTokenHelper::IsSystemApp() || isSubsystem);
98 if (isSubsystem) {
99 return PublishNotificationBySa(request);
100 }
101 CheckRemovalWantAgent(request);
102 do {
103 result = publishProcess_[request->GetSlotType()]->PublishNotificationByApp(request);
104 if (result != ERR_OK) {
105 break;
106 }
107
108 sptr<NotificationBundleOption> bundleOption;
109 result = PrepareNotificationInfo(request, bundleOption);
110 if (result != ERR_OK) {
111 message.ErrorCode(result).Message("PrepareNotificationInfo failed.");
112 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
113 break;
114 }
115
116 result = CheckSoundPermission(request, bundleOption);
117 if (result != ERR_OK) {
118 message.ErrorCode(result).Message("Check sound failed.");
119 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
120 break;
121 }
122
123 #ifndef IS_EMULATOR
124 if (IsNeedPushCheck(request)) {
125 result = PushCheck(request);
126 }
127 #endif
128
129 if (result != ERR_OK) {
130 break;
131 }
132 result = PublishPreparedNotification(request, bundleOption, isUpdateByOwnerAllowed);
133 if (result != ERR_OK) {
134 break;
135 }
136 } while (0);
137
138 NotificationAnalyticsUtil::ReportAllBundlesSlotEnabled();
139 SendPublishHiSysEvent(request, result);
140 return result;
141 }
142
SetChainIdToExtraInfo(const sptr<NotificationRequest> & request,OHOS::HiviewDFX::HiTraceId traceId)143 void AdvancedNotificationService::SetChainIdToExtraInfo
144 (const sptr<NotificationRequest> &request, OHOS::HiviewDFX::HiTraceId traceId)
145 {
146 std::shared_ptr<AAFwk::WantParams> additionalData = request->GetAdditionalData();
147 if (!additionalData) {
148 additionalData = std::make_shared<AAFwk::WantParams>();
149 }
150 std::stringstream chainId;
151 chainId << std::hex << traceId.GetChainId();
152 std::string hexTransId;
153 chainId >> std::hex >> hexTransId;
154 additionalData->SetParam("_oh_ans_sys_traceid", AAFwk::String::Box(hexTransId));
155 request->SetAdditionalData(additionalData);
156 }
157
PublishNotificationForIndirectProxyWithMaxCapacity(const sptr<NotificationRequest> & request)158 ErrCode AdvancedNotificationService::PublishNotificationForIndirectProxyWithMaxCapacity(
159 const sptr<NotificationRequest>& request)
160 {
161 return PublishNotificationForIndirectProxy(request);
162 }
163
PublishNotificationForIndirectProxy(const sptr<NotificationRequest> & request)164 ErrCode AdvancedNotificationService::PublishNotificationForIndirectProxy(const sptr<NotificationRequest> &request)
165 {
166 NOTIFICATION_HITRACE(HITRACE_TAG_NOTIFICATION);
167 TraceChainUtil traceChain = TraceChainUtil();
168 OHOS::HiviewDFX::HiTraceId traceId = OHOS::HiviewDFX::HiTraceChain::GetId();
169 ANS_LOGD("called");
170
171 auto fullTokenID = IPCSkeleton::GetCallingFullTokenID();
172 if (Security::AccessToken::AccessTokenKit::IsAtomicServiceByFullTokenID(fullTokenID)) {
173 ANS_LOGE("AtomicService is not allowed to publish notification");
174 return ERR_ANS_PERMISSION_DENIED;
175 }
176
177 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_9, EventBranchId::BRANCH_0);
178 if (!request) {
179 ANS_LOGE("null request");
180 message.ErrorCode(ERR_ANS_INVALID_PARAM).Message("Request object is nullptr");
181 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
182 return ERR_ANS_INVALID_PARAM;
183 }
184 SetChainIdToExtraInfo(request, traceId);
185 ErrCode result = PrePublishRequest(request);
186 if (result != ERR_OK) {
187 return result;
188 }
189 auto tokenCaller = IPCSkeleton::GetCallingTokenID();
190 bool isSystemApp = AccessTokenHelper::IsSystemApp();
191 bool isSubsystem = AccessTokenHelper::VerifyNativeToken(tokenCaller);
192 if (!isSystemApp && !isSubsystem && request->GetExtendInfo() != nullptr) {
193 request->SetExtendInfo(nullptr);
194 }
195 bool isAgentController = AccessTokenHelper::VerifyCallerPermission(tokenCaller,
196 OHOS_PERMISSION_NOTIFICATION_AGENT_CONTROLLER);
197 // SA not support sound
198 if (!request->GetSound().empty()) {
199 request->SetSound("");
200 }
201 std::string bundle = request->GetCreatorBundleName();
202 int32_t uid = request->GetCreatorUid();
203 request->SetOwnerUid(uid);
204 request->SetOwnerBundleName(bundle);
205 std::shared_ptr<NotificationRecord> record = std::make_shared<NotificationRecord>();
206 record->request = request;
207 record->isThirdparty = false;
208 record->bundleOption = new (std::nothrow) NotificationBundleOption(bundle, uid);
209 sptr<NotificationBundleOption> bundleOption = new (std::nothrow) NotificationBundleOption(bundle, uid);
210 if (record->bundleOption == nullptr || bundleOption == nullptr) {
211 ANS_LOGE("null bundleOption");
212 message.ErrorCode(ERR_ANS_NO_MEMORY).Message("Failed to create bundleOption");
213 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
214 return ERR_ANS_NO_MEMORY;
215 }
216 record->bundleOption->SetAppInstanceKey(request->GetAppInstanceKey());
217 record->notification = new (std::nothrow) Notification(request);
218 if (record->notification == nullptr) {
219 ANS_LOGE("null notification");
220 message.ErrorCode(ERR_ANS_NO_MEMORY).Message("Failed to create notification");
221 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
222 return ERR_ANS_NO_MEMORY;
223 }
224
225 if (notificationSvrQueue_ == nullptr) {
226 ANS_LOGE("null notificationSvrQueue");
227 message.ErrorCode(ERR_ANS_NO_MEMORY).Message("Serial queue is invalid.");
228 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
229 return ERR_ANS_INVALID_PARAM;
230 }
231
232 SetRequestBySlotType(record->request, bundleOption);
233
234 const int32_t ipcUid = IPCSkeleton::GetCallingUid();
235 ffrt::task_handle handler = notificationSvrQueue_->submit_h([&]() {
236 if (IsDisableNotification(bundle)) {
237 ANS_LOGE("bundle in Disable Notification list, bundleName=%{public}s", bundle.c_str());
238 result = ERR_ANS_REJECTED_WITH_DISABLE_NOTIFICATION;
239 message.BranchId(EventBranchId::BRANCH_1)
240 .ErrorCode(result).Message("bundle in Disable Notification list, bundleName=" + bundle);
241 return;
242 }
243 if (IsDisableNotificationByKiosk(bundle)) {
244 ANS_LOGE("bundle not in kiosk trust list, bundleName=%{public}s", bundle.c_str());
245 result = ERR_ANS_REJECTED_WITH_DISABLE_NOTIFICATION;
246 return;
247 }
248 if (AssignValidNotificationSlot(record, bundleOption) != ERR_OK) {
249 ANS_LOGE("Can not assign valid slot!");
250 }
251 result = Filter(record);
252 if (result != ERR_OK) {
253 ANS_LOGE("Reject by filters: %{public}d", result);
254 return;
255 }
256
257 if (!request->IsDoNotDisturbByPassed()) {
258 CheckDoNotDisturbProfile(record);
259 }
260 ChangeNotificationByControlFlags(record, isAgentController);
261 if (IsSaCreateSystemLiveViewAsBundle(record, ipcUid) &&
262 (std::static_pointer_cast<OHOS::Notification::NotificationLocalLiveViewContent>(
263 record->request->GetContent()->GetNotificationContent())->GetType() == TYPE_CODE_DOWNLOAD)) {
264 result = SaPublishSystemLiveViewAsBundle(record);
265 if (result == ERR_OK) {
266 SendLiveViewUploadHiSysEvent(record, UploadStatus::CREATE);
267 }
268 return;
269 }
270
271 bool isNotificationExists = IsNotificationExists(record->notification->GetKey());
272 result = FlowControlService::GetInstance().FlowControl(record, ipcUid, isNotificationExists);
273 if (result != ERR_OK) {
274 message.BranchId(EventBranchId::BRANCH_5).ErrorCode(result).Message("publish failed with FlowControl");
275 return;
276 }
277 if (AssignToNotificationList(record) != ERR_OK) {
278 ANS_LOGE("Failed to assign notification list");
279 message.BranchId(EventBranchId::BRANCH_5).ErrorCode(result).Message("Failed to assign notification list");
280 return;
281 }
282
283 sptr<NotificationSortingMap> sortingMap = GenerateSortingMap();
284 NotificationSubscriberManager::GetInstance()->NotifyConsumed(record->notification, sortingMap);
285 if ((record->request->GetAutoDeletedTime() > GetCurrentTime()) && !record->request->IsCommonLiveView()) {
286 StartAutoDeletedTimer(record);
287 }
288 });
289 notificationSvrQueue_->wait(handler);
290 if (result != ERR_OK) {
291 NotificationAnalyticsUtil::ReportPublishFailedEvent(request, message);
292 return result;
293 }
294 return ERR_OK;
295 }
296
PublishAsBundle(const sptr<NotificationRequest> & notification,const std::string & representativeBundle)297 ErrCode AdvancedNotificationService::PublishAsBundle(
298 const sptr<NotificationRequest>& notification, const std::string &representativeBundle)
299 {
300 return ERR_INVALID_OPERATION;
301 }
302
PublishAsBundleWithMaxCapacity(const sptr<NotificationRequest> & notification,const std::string & representativeBundle)303 ErrCode AdvancedNotificationService::PublishAsBundleWithMaxCapacity(
304 const sptr<NotificationRequest>& notification, const std::string &representativeBundle)
305 {
306 return PublishAsBundle(notification, representativeBundle);
307 }
308
PublishContinuousTaskNotification(const sptr<NotificationRequest> & request)309 ErrCode AdvancedNotificationService::PublishContinuousTaskNotification(const sptr<NotificationRequest> &request)
310 {
311 ANS_LOGD("called");
312
313 bool isSubsystem = AccessTokenHelper::VerifyNativeToken(IPCSkeleton::GetCallingTokenID());
314 if (!isSubsystem) {
315 return ERR_ANS_NOT_SYSTEM_SERVICE;
316 }
317
318 int32_t uid = IPCSkeleton::GetCallingUid();
319 int32_t userId = SUBSCRIBE_USER_INIT;
320 OHOS::AccountSA::OsAccountManager::GetOsAccountLocalIdFromUid(uid, userId);
321 request->SetCreatorUserId(userId);
322 ANS_LOGD("%{public}s, uid=%{public}d userId=%{public}d", __FUNCTION__, uid, userId);
323
324 if (request->GetCreatorBundleName().empty()) {
325 request->SetCreatorBundleName(FOUNDATION_BUNDLE_NAME);
326 }
327
328 if (request->GetOwnerBundleName().empty()) {
329 request->SetOwnerBundleName(FOUNDATION_BUNDLE_NAME);
330 }
331
332 sptr<NotificationBundleOption> bundleOption = nullptr;
333 bundleOption = new (std::nothrow) NotificationBundleOption(std::string(), uid);
334 if (bundleOption == nullptr) {
335 ANS_LOGE("null bundleOption");
336 return ERR_NO_MEMORY;
337 }
338
339 ErrCode result = PrepareContinuousTaskNotificationRequest(request, uid);
340 if (result != ERR_OK) {
341 return result;
342 }
343 request->SetUnremovable(true);
344 std::shared_ptr<NotificationRecord> record = std::make_shared<NotificationRecord>();
345 record->request = request;
346 record->bundleOption = bundleOption;
347 record->notification = new (std::nothrow) Notification(request);
348 if (record->notification == nullptr) {
349 ANS_LOGE("null notification");
350 return ERR_NO_MEMORY;
351 }
352 record->notification->SetSourceType(NotificationConstant::SourceType::TYPE_CONTINUOUS);
353
354 if (notificationSvrQueue_ == nullptr) {
355 ANS_LOGE("null notificationSvrQueue");
356 return ERR_ANS_INVALID_PARAM;
357 }
358 ffrt::task_handle handler = notificationSvrQueue_->submit_h(std::bind([&]() {
359 ANS_LOGD("called");
360 if (!IsNotificationExists(record->notification->GetKey())) {
361 AddToNotificationList(record);
362 } else {
363 if (record->request->IsAlertOneTime()) {
364 CloseAlert(record);
365 }
366 UpdateInNotificationList(record);
367 }
368
369 UpdateRecentNotification(record->notification, false, 0);
370 sptr<NotificationSortingMap> sortingMap = GenerateSortingMap();
371 NotificationSubscriberManager::GetInstance()->NotifyConsumed(record->notification, sortingMap);
372 }));
373 notificationSvrQueue_->wait(handler);
374
375 return result;
376 }
377
UpdateNotificationTimerByUid(const int32_t uid,const bool isPaused)378 ErrCode AdvancedNotificationService::UpdateNotificationTimerByUid(const int32_t uid, const bool isPaused)
379 {
380 bool isSubSystem = AccessTokenHelper::VerifyNativeToken(IPCSkeleton::GetCallingTokenID());
381 int32_t callingUid = IPCSkeleton::GetCallingUid();
382 if (!isSubSystem || callingUid != RESSCHED_UID) {
383 ANS_LOGE(" callingUid: %{public}d", callingUid);
384 return ERR_ANS_NOT_SYSTEM_SERVICE;
385 }
386
387 if (!notificationSvrQueue_) {
388 ANS_LOGE("null notificationSvrQueue");
389 return ERR_ANS_INVALID_PARAM;
390 }
391 ffrt::task_handle handler = notificationSvrQueue_->submit_h(std::bind([&]() {
392 HandleUpdateLiveViewNotificationTimer(uid, isPaused);
393 }));
394 notificationSvrQueue_->wait(handler);
395 return ERR_OK;
396 }
397
CheckNotificationRequest(const sptr<NotificationRequest> & request)398 ErrCode AdvancedNotificationService::CheckNotificationRequest(const sptr<NotificationRequest> &request)
399 {
400 if (!request) {
401 ANSR_LOGE("null request");
402 return ERR_ANS_INVALID_PARAM;
403 }
404 auto tokenCaller = IPCSkeleton::GetCallingTokenID();
405 bool isSystemApp = AccessTokenHelper::IsSystemApp();
406 bool isSubsystem = AccessTokenHelper::VerifyNativeToken(tokenCaller);
407 bool isAgentController = AccessTokenHelper::VerifyCallerPermission(tokenCaller,
408 OHOS_PERMISSION_NOTIFICATION_AGENT_CONTROLLER);
409
410 const auto wantAgent = request->GetWantAgent();
411 const auto removalWantAgent = request->GetRemovalWantAgent();
412
413 auto content = request->GetContent();
414 if (content != nullptr && content->GetContentType() == NotificationContent::Type::MULTILINE) {
415 ErrCode checkCode = CheckNotificationRequestLineWantAgents(content, isAgentController,
416 isSystemApp || isSubsystem);
417 if (checkCode != ERR_OK) {
418 return checkCode;
419 }
420 }
421
422 const auto isLocalWantAgent = (wantAgent != nullptr && wantAgent->IsLocal()) ||
423 (removalWantAgent != nullptr && removalWantAgent->IsLocal());
424 if (isLocalWantAgent && !(isSystemApp || isSubsystem)) {
425 ANS_LOGE("Local wantAgent does not support non system app");
426 return ERR_ANS_NON_SYSTEM_APP;
427 }
428
429 if (isLocalWantAgent && !isAgentController) {
430 ANS_LOGE("Local wantAgent does not support permission denied");
431 return ERR_ANS_PERMISSION_DENIED;
432 }
433 if (!isSystemApp && !isSubsystem && request->GetExtendInfo() != nullptr) {
434 request->SetExtendInfo(nullptr);
435 }
436 return ERR_OK;
437 }
438
CheckNotificationRequestLineWantAgents(const std::shared_ptr<NotificationContent> & content,bool isAgentController,bool isSystemComp)439 ErrCode AdvancedNotificationService::CheckNotificationRequestLineWantAgents(
440 const std::shared_ptr<NotificationContent> &content, bool isAgentController, bool isSystemComp)
441 {
442 auto multiLineContent =
443 std::static_pointer_cast<NotificationMultiLineContent>(content->GetNotificationContent());
444 if (multiLineContent != nullptr) {
445 auto lineWantAgents = multiLineContent->GetLineWantAgents();
446 if (lineWantAgents.size() > 0) {
447 if (!isSystemComp) {
448 ANS_LOGE("Local wantAgent does not support non system app");
449 return ERR_ANS_NON_SYSTEM_APP;
450 }
451 if (!isAgentController) {
452 ANS_LOGE("LineWantAgents does not support permission denied");
453 return ERR_ANS_PERMISSION_DENIED;
454 }
455 }
456 }
457 return ERR_OK;
458 }
459 } // Notification
460 } // OHOS