diff --git a/frameworks/ans/BUILD.gn b/frameworks/ans/BUILD.gn index 837a2878d4270809877902f1ee5f946453ac301a..d8cc99e8758b2c7c4cc25ac35d6d5673c01a7950 100644 --- a/frameworks/ans/BUILD.gn +++ b/frameworks/ans/BUILD.gn @@ -90,6 +90,7 @@ ohos_shared_library("ans_innerkits") { "${frameworks_module_ans_path}/src/notification_do_not_disturb_profile.cpp", "${frameworks_module_ans_path}/src/notification_flags.cpp", "${frameworks_module_ans_path}/src/notification_helper.cpp", + "${frameworks_module_ans_path}/src/notification_icon_button.cpp", "${frameworks_module_ans_path}/src/notification_live_view_content.cpp", "${frameworks_module_ans_path}/src/notification_local_live_view_button.cpp", "${frameworks_module_ans_path}/src/notification_local_live_view_content.cpp", diff --git a/frameworks/ans/src/notification_capsule.cpp b/frameworks/ans/src/notification_capsule.cpp index a1be9fcc45499ad3b05e6677a8a0bf04c7a1a065..caf02024c94f2d2772106d024b9bed2264325b17 100644 --- a/frameworks/ans/src/notification_capsule.cpp +++ b/frameworks/ans/src/notification_capsule.cpp @@ -68,6 +68,26 @@ std::string NotificationCapsule::GetContent() const return content_; } +std::vector NotificationCapsule::GetCapsuleButton() const +{ + return capsuleButton_; +} + +void NotificationCapsule::SetCapsuleButton(const std::vector &buttons) +{ + capsuleButton_ = buttons; +} + +int32_t NotificationCapsule::GetTime() const +{ + return time_; +} + +void NotificationCapsule::SetTime(int32_t time) +{ + time_ = time; +} + std::string NotificationCapsule::Dump() { return "Capsule{ " @@ -75,6 +95,7 @@ std::string NotificationCapsule::Dump() ", backgroundColor = " + backgroundColor_ + ", content = " + content_ + ", icon = " + (icon_ ? "not null" : "null") + + ", time = " + std::to_string(time_) + " }"; } @@ -85,6 +106,18 @@ bool NotificationCapsule::ToJson(nlohmann::json &jsonObject) const jsonObject["content"] = content_; jsonObject["icon"] = AnsImageUtil::PackImage(icon_); + jsonObject["time"] = time_; + nlohmann::json capsuleBtnArr = nlohmann::json::array(); + for (auto btn : capsuleButton_) { + nlohmann::json capsuleBtnObj; + if (!NotificationJsonConverter::ConvertToJson(&btn, capsuleBtnObj)) { + ANS_LOGE("Cannot convert button to JSON"); + return false; + } + capsuleBtnArr.emplace_back(capsuleBtnObj); + } + jsonObject["capsuleButton"] = capsuleBtnArr; + return true; } @@ -119,6 +152,24 @@ NotificationCapsule *NotificationCapsule::FromJson(const nlohmann::json &jsonObj capsule->icon_ = AnsImageUtil::UnPackImage(pmStr); } + if (jsonObject.find("time") != jsonEnd && jsonObject.at("time").is_number_integer()) { + capsule->time_ = jsonObject.at("time").get(); + } + + if (jsonObject.find("capsuleButton") != jsonEnd && jsonObject.at("capsuleButton").is_array()) { + std::vector cardButtons; + for (auto &item : jsonObject.at("capsuleButton").items()) { + nlohmann::json cardBtnObject = item.value(); + auto pButton = NotificationJsonConverter::ConvertFromJson(cardBtnObject); + if (pButton != nullptr) { + cardButtons.push_back(*pButton); + delete pButton; + pButton = nullptr; + } + } + capsule->capsuleButton_ = cardButtons; + } + return capsule; } @@ -152,6 +203,32 @@ bool NotificationCapsule::Marshalling(Parcel &parcel) const } } + if (!parcel.WriteInt32(time_)) { + ANS_LOGE("Write time_ fail."); + return false; + } + + parcel.WriteInt32(static_cast(capsuleButton_.size())); + for (const auto& button : capsuleButton_) { + if (!parcel.WriteParcelable(&button)) { + ANS_LOGE("Failed to write card button"); + return false; + } + } + + if (!parcel.WriteInt32(time_)) { + ANS_LOGE("Write time_ fail."); + return false; + } + + parcel.WriteInt32(static_cast(capsuleButton_.size())); + for (const auto& button : capsuleButton_) { + if (!parcel.WriteParcelable(&button)) { + ANS_LOGE("Failed to write card button"); + return false; + } + } + return true; } @@ -170,6 +247,25 @@ bool NotificationCapsule::ReadFromParcel(Parcel &parcel) } } + if (!parcel.ReadInt32(time_)) { + ANS_LOGE("Read time_ failed."); + return false; + } + + auto vsize = parcel.ReadInt32(); + vsize = (vsize < BUTTON_MAX_SIZE) ? vsize : BUTTON_MAX_SIZE; + capsuleButton_.clear(); + for (int i = 0; i < vsize; ++i) { + auto btn = parcel.ReadParcelable(); + if (btn == nullptr) { + ANS_LOGE("Failed to read card button"); + return false; + } + capsuleButton_.push_back(*btn); + delete btn; + btn = nullptr; + } + return true; } diff --git a/frameworks/ans/src/notification_icon_button.cpp b/frameworks/ans/src/notification_icon_button.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfff83497dd89516db982ab5a93e8ea9e353a31b --- /dev/null +++ b/frameworks/ans/src/notification_icon_button.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "notification_icon_button.h" + +#include // for basic_string, operator+, basic_string<>... +#include // for shared_ptr, shared_ptr<>::element_type +#include + + +#include "ans_image_util.h" +#include "ans_log_wrapper.h" +#include "nlohmann/json.hpp" // for json, basic_json<>::object_t, basic_json +#include "parcel.h" // for Parcel + +namespace OHOS { +namespace Notification { +using ResourceVectorPtr = std::vector>; + +const std::shared_ptr NotificationIconButton::GetIconResource() const +{ + return iconResource_; +} + +void NotificationIconButton::SetIconResource(const std::shared_ptr &iconResource) +{ + iconResource_ = iconResource; +} + + +std::string NotificationIconButton::GetText() const +{ + return text_; +} + +void NotificationIconButton::SetText(const std::string &text) +{ + text_ = text; +} + +std::string NotificationIconButton::GetName() const +{ + return name_; +} + +void NotificationIconButton::SetName(const std::string &name) +{ + name_ = name; +} + +bool NotificationIconButton::GetHidePanel() const +{ + return hidePanel_; +} + +void NotificationIconButton::SetHidePanel(bool hidePanel) +{ + hidePanel_ = hidePanel; +} + +void NotificationIconButton::ClearButtonIconsResource() +{ +} + +std::string NotificationIconButton::Dump() +{ + return "NotificationIconButton {" + "name = " + name_ + + ", text = " + text_ + + ", hidePanel = " + std::to_string(hidePanel_) + + " }"; +} + +bool NotificationIconButton::ToJson(nlohmann::json &jsonObject) const +{ + jsonObject["text"] = text_; + jsonObject["name"] = name_; + jsonObject["hidePanel"] = hidePanel_; + + nlohmann::json resourceObj; + resourceObj["id"] = iconResource_->id; + resourceObj["bundleName"] = iconResource_->bundleName; + resourceObj["moduleName"] = iconResource_->moduleName; + jsonObject["iconResource"] = resourceObj; + return true; +} + +NotificationIconButton *NotificationIconButton::FromJson(const nlohmann::json &jsonObject) +{ + if (jsonObject.is_null() or !jsonObject.is_object()) { + ANS_LOGE("Invalid JSON object"); + return nullptr; + } + + auto *button = new (std::nothrow) NotificationIconButton(); + if (button == nullptr) { + ANS_LOGE("Failed to create icon button"); + return nullptr; + } + + const auto &jsonEnd = jsonObject.cend(); + if (jsonObject.find("text") != jsonEnd && jsonObject.at("text").is_string()) { + button->SetText(jsonObject.at("text").get()); + } + + if (jsonObject.find("name") != jsonEnd && jsonObject.at("name").is_string()) { + button->SetName(jsonObject.at("name").get()); + } + + if (jsonObject.find("hidePanel") != jsonEnd && jsonObject.at("hidePanel").is_boolean()) { + button->SetHidePanel(jsonObject.at("hidePanel").get()); + } + + if (jsonObject.find("iconResource") != jsonEnd) { + auto resources = jsonObject.at("iconResource"); + auto resourceObj = std::make_shared(); + if (ResourceFromJson(resources, resourceObj)) { + button->SetIconResource(resourceObj); + } + } + return button; +} + +bool NotificationIconButton::ResourceFromJson(const nlohmann::json &resource, + std::shared_ptr& resourceObj) +{ + const auto &jsonEnd = resource.cend(); + int resourceCount = BUTTON_RESOURCE_SIZE; + if (resource.find("bundleName") != jsonEnd && resource.at("bundleName").is_string()) { + resourceCount--; + resourceObj->bundleName = resource.at("bundleName").get(); + } + if (resource.find("moduleName") != jsonEnd && resource.at("moduleName").is_string()) { + resourceCount--; + resourceObj->moduleName = resource.at("moduleName").get(); + } + if (resource.find("id") != jsonEnd && resource.at("id").is_number_integer()) { + resourceCount--; + resourceObj->id = resource.at("id").get(); + } + if (resourceCount == 0) { + return true; + } + ANS_LOGE("Resource from json failed."); + return false; +} + +bool NotificationIconButton::Marshalling(Parcel &parcel) const +{ + if (!parcel.WriteString(text_)) { + ANS_LOGE("Failed to write text"); + return false; + } + + if (!parcel.WriteString(name_)) { + ANS_LOGE("Failed to write name"); + return false; + } + + if (!parcel.WriteBool(hidePanel_)) { + ANS_LOGE("Failed to write hidePanel"); + return false; + } + + std::vector iconsResource = {}; + iconsResource.push_back(iconResource_->bundleName); + iconsResource.push_back(iconResource_->moduleName); + iconsResource.push_back(std::to_string(iconResource_->id)); + if (!parcel.WriteStringVector(iconsResource)) { + ANS_LOGE("Failed to write button icon resource"); + return false; + } + return true; +} + +NotificationIconButton *NotificationIconButton::Unmarshalling(Parcel &parcel) +{ + NotificationIconButton *button = new (std::nothrow) NotificationIconButton(); + + if (button && !button->ReadFromParcel(parcel)) { + delete button; + button = nullptr; + } + return button; +} + +bool NotificationIconButton::ReadFromParcel(Parcel &parcel) +{ + if (!parcel.ReadString(text_)) { + ANS_LOGE("Failed to read text"); + return false; + } + + if (!parcel.ReadString(name_)) { + ANS_LOGE("Failed to read name"); + return false; + } + + if (!parcel.ReadBool(hidePanel_)) { + ANS_LOGE("Failed to read hidePanel"); + return false; + } + + std::vector iconsResource; + if (!parcel.ReadStringVector(&iconsResource)) { + ANS_LOGE("Failed to read button names"); + return false; + } + if (iconsResource.size() < BUTTON_RESOURCE_SIZE) { + ANS_LOGE("Invalid input for button icons resource"); + return false; + } + auto resource = std::make_shared(); + resource->bundleName = iconsResource[RESOURCE_BUNDLENAME_INDEX]; + resource->moduleName = iconsResource[RESOURCE_MODULENAME_INDEX]; + std::stringstream sin(iconsResource[RESOURCE_ID_INDEX]); + int32_t checknum; + if (!(sin >> checknum)) { + ANS_LOGE("Invalid input for button icons resource"); + return false; + } + resource->id = std::stoi(iconsResource[RESOURCE_ID_INDEX]); + iconResource_ = resource; + + return true; +} +} +} \ No newline at end of file diff --git a/frameworks/ans/src/notification_local_live_view_content.cpp b/frameworks/ans/src/notification_local_live_view_content.cpp index 697fa5026d5b5b59f4c8c4d8a83cbe06c3f1052b..e2686c159fe2ff8b274b37c96ab898888d2069d1 100644 --- a/frameworks/ans/src/notification_local_live_view_content.cpp +++ b/frameworks/ans/src/notification_local_live_view_content.cpp @@ -65,6 +65,16 @@ NotificationLocalLiveViewButton NotificationLocalLiveViewContent::GetButton() return button_; } +void NotificationLocalLiveViewContent::SetCardButton(std::vector buttons) +{ + card_button_ = buttons; +} + +std::vector NotificationLocalLiveViewContent::GetCardButton() +{ + return card_button_; +} + void NotificationLocalLiveViewContent::SetProgress(NotificationProgress progress) { progress_ = progress; @@ -100,6 +110,16 @@ bool NotificationLocalLiveViewContent::isFlagExist(int32_t flag) } } +void NotificationLocalLiveViewContent::SetLiveviewType(int32_t type) +{ + liveviewType_ = type; +} + +int32_t NotificationLocalLiveViewContent::GetLiveviewType() +{ + return liveviewType_; +} + std::string NotificationLocalLiveViewContent::Dump() { return "NotificationLocalLiveViewContent{ " + NotificationBasicContent::Dump() + @@ -108,6 +128,7 @@ std::string NotificationLocalLiveViewContent::Dump() ", button = " + button_.Dump() + ", progress = " + progress_.Dump() + ", time = " + time_.Dump() + + ", liveviewType = " + std::to_string(liveviewType_) + " }"; } @@ -142,12 +163,24 @@ bool NotificationLocalLiveViewContent::ToJson(nlohmann::json &jsonObject) const return false; } + nlohmann::json cardBtnArr = nlohmann::json::array(); + for (auto btn : card_button_) { + nlohmann::json cardBtnObj; + if (!NotificationJsonConverter::ConvertToJson(&btn, cardBtnObj)) { + ANS_LOGE("Cannot convert button to JSON"); + return false; + } + cardBtnArr.emplace_back(cardBtnObj); + } + jsonObject["type"] = type_; jsonObject["capsule"] = capsuleObj; jsonObject["button"] = buttonObj; + jsonObject["cardButton"] = cardBtnArr; jsonObject["progress"] = progressObj; jsonObject["time"] = timeObj; jsonObject["flags"] = nlohmann::json(flags_); + jsonObject["liveviewType"] = liveviewType_; return true; } @@ -192,6 +225,20 @@ NotificationLocalLiveViewContent *NotificationLocalLiveViewContent::FromJson(con } } + if (jsonObject.find("cardButton") != jsonEnd && jsonObject.at("cardButton").is_array()) { + std::vector cardButtons; + for (auto &item : jsonObject.at("cardButton").items()) { + nlohmann::json cardBtnObject = item.value(); + auto pButton = NotificationJsonConverter::ConvertFromJson(cardBtnObject); + if (pButton != nullptr) { + cardButtons.push_back(*pButton); + delete pButton; + pButton = nullptr; + } + } + pContent->card_button_ = cardButtons; + } + if (jsonObject.find("progress") != jsonEnd) { auto progressObj = jsonObject.at("progress"); auto pProgress = NotificationJsonConverter::ConvertFromJson(progressObj); @@ -216,6 +263,10 @@ NotificationLocalLiveViewContent *NotificationLocalLiveViewContent::FromJson(con pContent->flags_ = jsonObject.at("flags").get>(); } + if (jsonObject.find("liveviewType") != jsonEnd && jsonObject.at("liveviewType").is_number_integer()) { + pContent->liveviewType_ = jsonObject.at("liveviewType").get(); + } + return pContent; } @@ -245,6 +296,14 @@ bool NotificationLocalLiveViewContent::Marshalling(Parcel &parcel) const return false; } + parcel.WriteInt32(static_cast(card_button_.size())); + for (const auto& button : card_button_) { + if (!parcel.WriteParcelable(&button)) { + ANS_LOGE("Failed to write card button"); + return false; + } + } + if (!parcel.WriteParcelable(&progress_)) { ANS_LOGE("Failed to write progress"); return false; @@ -260,6 +319,11 @@ bool NotificationLocalLiveViewContent::Marshalling(Parcel &parcel) const return false; } + if (!parcel.WriteInt32(liveviewType_)) { + ANS_LOGE("Write liveviewType fail."); + return false; + } + return true; } @@ -304,6 +368,20 @@ bool NotificationLocalLiveViewContent::ReadFromParcel(Parcel &parcel) delete pButton; pButton = nullptr; + auto vsize = parcel.ReadInt32(); + vsize = (vsize < BUTTON_MAX_SIZE) ? vsize : BUTTON_MAX_SIZE; + card_button_.clear(); + for (int i = 0; i < vsize; ++i) { + auto btn = parcel.ReadParcelable(); + if (btn == nullptr) { + ANS_LOGE("Failed to read card button"); + return false; + } + card_button_.push_back(*btn); + delete btn; + btn = nullptr; + } + auto pProgress = parcel.ReadParcelable(); if (pProgress == nullptr) { ANS_LOGE("Failed to read progress"); @@ -327,6 +405,11 @@ bool NotificationLocalLiveViewContent::ReadFromParcel(Parcel &parcel) return false; } + if (!parcel.ReadInt32(liveviewType_)) { + ANS_LOGE("Read liveviewType_ failed."); + return false; + } + return true; } diff --git a/frameworks/ans/test/unittest/BUILD.gn b/frameworks/ans/test/unittest/BUILD.gn index d6a5b2f1e7025f8ae7e58ba2aa1fa7b313637558..875032e8c10828d159950a74049ffbba53d66ad6 100644 --- a/frameworks/ans/test/unittest/BUILD.gn +++ b/frameworks/ans/test/unittest/BUILD.gn @@ -46,6 +46,7 @@ ohos_unittest("ans_reminder_unit_test") { "${frameworks_module_ans_path}/test/unittest/notification_do_not_disturb_profile_test.cpp", "${frameworks_module_ans_path}/test/unittest/notification_flags_test.cpp", "${frameworks_module_ans_path}/test/unittest/notification_helper_test.cpp", + "${frameworks_module_ans_path}/test/unittest/notification_icon_button_test.cpp", "${frameworks_module_ans_path}/test/unittest/notification_live_view_content_test.cpp", "${frameworks_module_ans_path}/test/unittest/notification_local_live_view_button_test.cpp", "${frameworks_module_ans_path}/test/unittest/notification_local_live_view_content_test.cpp", diff --git a/frameworks/ans/test/unittest/notification_icon_button_test.cpp b/frameworks/ans/test/unittest/notification_icon_button_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47219fb79d1b5b0c18c3192efe00fce74b4ec044 --- /dev/null +++ b/frameworks/ans/test/unittest/notification_icon_button_test.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "notification_icon_button.h" +#include "ans_image_util.h" + +using namespace testing::ext; +namespace OHOS { +namespace Notification { +class NotificationIconButtonTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() {} + void TearDown() {} +}; + +/** + * @tc.name: ToJson_00001 + * @tc.desc: Test ToJson parameters. + * @tc.type: FUNC + * @tc.require: issueI5WBBH + */ +HWTEST_F(NotificationIconButtonTest, ToJson_00001, Function | SmallTest | Level1) +{ + nlohmann::json jsonObject; + auto rrc = std::make_shared(); + rrc->FromJson(jsonObject); + EXPECT_EQ(rrc->ToJson(jsonObject), true); +} + +/** + * @tc.name: FromJson_00001 + * @tc.desc: Test FromJson parameters. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(NotificationIconButtonTest, FromJson_00001, Function | SmallTest | Level1) +{ + auto rrc = std::make_shared(); + nlohmann::json jsonObject = nlohmann::json{"testjson"}; + EXPECT_EQ(jsonObject.is_object(), false); + EXPECT_EQ(rrc->FromJson(jsonObject), nullptr); +} + +/** + * @tc.name: FromJson_00002 + * @tc.desc: Test FromJson parameters. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(NotificationIconButtonTest, FromJson_00002, Function | SmallTest | Level1) +{ + auto rrc = std::make_shared(); + nlohmann::json jsonObject = nlohmann::json{{"names", {"test"}}, {"icons", {}}}; + EXPECT_EQ(jsonObject.is_object(), true); + EXPECT_NE(rrc->FromJson(jsonObject), nullptr); +} + +/** + * @tc.name: FromJson_00003 + * @tc.desc: Test FromJson parameters. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(NotificationIconButtonTest, FromJson_00003, Function | SmallTest | Level1) +{ + auto rrc = std::make_shared(); + nlohmann::json jsonObject = nlohmann::json{{"names", {"test"}}, {"icons", {1, "testIcons"}}}; + EXPECT_EQ(jsonObject.is_object(), true); + EXPECT_EQ(rrc->FromJson(jsonObject), nullptr); +} + +/** + * @tc.name: Marshalling_00002 + * @tc.desc: Test Marshalling parameters. + * @tc.type: FUNC + * @tc.require: issueI5WBBH + */ +HWTEST_F(NotificationIconButtonTest, Marshalling_00002, Function | SmallTest | Level1) +{ + Parcel parcel; + auto button = std::make_shared(); + button->SetText("test"); + EXPECT_EQ(button->Marshalling(parcel), true); +} + +/** + * @tc.name: Marshalling_00001 + * @tc.desc: Test Marshalling parameters. + * @tc.type: FUNC + * @tc.require: issueI5WBBH + */ +HWTEST_F(NotificationIconButtonTest, Marshalling_00001, Function | SmallTest | Level1) +{ + Parcel parcel; + auto rrc = std::make_shared(); + EXPECT_EQ(rrc->Marshalling(parcel), true); +} + +/** + * @tc.name: Unmarshalling_00001 + * @tc.desc: Test Unmarshalling parameters. + * @tc.type: FUNC + * @tc.require: issueI5WBBH + */ +HWTEST_F(NotificationIconButtonTest, Unmarshalling_00001, Function | SmallTest | Level1) +{ + bool unmarshalling = true; + Parcel parcel; + std::shared_ptr result = + std::make_shared(); + + if (nullptr != result) { + if (nullptr == result->Unmarshalling(parcel)) { + unmarshalling = false; + } + } + EXPECT_EQ(unmarshalling, true); +} + +/** + * @tc.name: Unmarshalling_00002 + * @tc.desc: Test Unmarshalling parameters. + * @tc.type: FUNC + * @tc.require: issueI5WBBH + */ +HWTEST_F(NotificationIconButtonTest, Unmarshalling_00002, Function | SmallTest | Level1) +{ + Parcel parcel; + auto button = std::make_shared(); + button->SetText("testText"); + button->SetName("testName"); + button->Marshalling(parcel); + + auto newButton = button->Unmarshalling(parcel); + EXPECT_NE(newButton, nullptr); +} + + +/** + * @tc.name: Dump_00001 + * @tc.desc: Test Dump. + * @tc.type: FUNC + * @tc.require: issue + */ +HWTEST_F(NotificationIconButtonTest, Dump_00001, Function | SmallTest | Level1) +{ + auto rrc = std::make_shared(); + + EXPECT_EQ(rrc->Dump(), ""); +} +} +} diff --git a/frameworks/js/napi/include/common.h b/frameworks/js/napi/include/common.h index b736bc8d1c17c22af6f7f872b2ceb464eeac928f..56c82321aa0002d79dc11db924a456684baf3ceb 100644 --- a/frameworks/js/napi/include/common.h +++ b/frameworks/js/napi/include/common.h @@ -458,6 +458,17 @@ public: */ static napi_value SetButton(const napi_env &env, const NotificationLocalLiveViewButton &button, napi_value &result); + /** + * @brief Sets a js object by specified NotificationIconButton array + * + * @param env Indicates the environment that the API is invoked under + * @param buttons Indicates a NotificationIconButton object to be converted + * @param result Indicates a js object to be set + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value SetCardButton(const napi_env &env, const std::vector buttons, + napi_value &result); + /** * @brief Sets a js object by specified NotificationProgress object * @@ -1317,6 +1328,41 @@ public: const napi_env &env, const napi_value &contentResult, std::shared_ptr content); + /** + * @brief Gets a card button of NotificationLocalLiveViewContent object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param contentResult Indicates a js object to be converted + * @param content Indicates a button object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewCardButton( + const napi_env &env, const napi_value &contentResult, + std::shared_ptr content); + + /** + * @brief Gets a capsule button of NotificationCapsule object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param capsuletResult Indicates a js object to be converted + * @param capsule Indicates a capsule object from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationLocalLiveViewCapsuleCardButton( + const napi_env &env, const napi_value &capsuletResult, + OHOS::Notification::NotificationCapsule &capsule); + + /** + * @brief Gets array of NotificationCapsule object from specified js object + * + * @param env Indicates the environment that the API is invoked under + * @param buttonResult Indicates a js array to be converted + * @param cardButtons Indicates a button array from specified js object + * @return Returns the null object if success, returns the null value otherwise + */ + static napi_value GetNotificationIconButton( + const napi_env &env, const napi_value &buttonResult, std::vector &cardButtons); + /** * @brief Gets a time of NotificationLocalLiveViewContent object from specified js object * @@ -1760,7 +1806,7 @@ public: const std::shared_ptr &agentBundle, napi_value &result); static napi_value GetResourceObject(napi_env env, std::shared_ptr &resource, napi_value &value); - static napi_value SetResourceObject(napi_env env, std::shared_ptr &resource, + static napi_value SetResourceObject(napi_env env, const std::shared_ptr &resource, napi_value &value); static napi_value SetObjectStringProperty(const napi_env &env, napi_value& object, const std::string& key, const std::string& value); diff --git a/frameworks/js/napi/src/common_convert_liveview.cpp b/frameworks/js/napi/src/common_convert_liveview.cpp index 167e82a8291cfece8b18764de9526cea96a456b9..ad4075cd3297dcf537fe3d52991950f770393fc8 100644 --- a/frameworks/js/napi/src/common_convert_liveview.cpp +++ b/frameworks/js/napi/src/common_convert_liveview.cpp @@ -24,6 +24,7 @@ #include "notification_capsule.h" #include "notification_constant.h" #include "notification_local_live_view_content.h" +#include "notification_icon_button.h" #include "notification_progress.h" #include "notification_time.h" #include "pixel_map_napi.h" @@ -78,6 +79,24 @@ napi_value Common::SetNotificationLocalLiveViewContent( napi_set_named_property(env, result, "button", button); } + // cardButton?: Array; + if (localLiveViewContent->isFlagExist(NotificationLocalLiveViewContent::LiveViewContentInner::CARD_BUTTON)) { + napi_value cardBtn = nullptr; + napi_create_array_with_length(env, localLiveViewContent->GetCardButton().size(), &cardBtn); + if (!SetCardButton(env, localLiveViewContent->GetCardButton(), cardBtn)) { + ANS_LOGE("SetCardButton call failed"); + return NapiGetBoolean(env, false); + } + napi_set_named_property(env, result, "cardButton", cardBtn); + } + + // liveViewType?: number + napi_create_int32(env, localLiveViewContent->GetLiveviewType(), &value); + if (localLiveViewContent->GetLiveviewType() != -1) { + ANS_LOGE("localLiveViewContent->GetLiveviewType() %{public}d ", localLiveViewContent->GetLiveviewType()); + napi_set_named_property(env, result, "liveViewType", value); + } + // progress: NotificationProgress if (localLiveViewContent->isFlagExist(NotificationLocalLiveViewContent::LiveViewContentInner::PROGRESS)) { napi_value progress = nullptr; @@ -136,6 +155,20 @@ napi_value Common::SetCapsule(const napi_env &env, const NotificationCapsule &ca napi_set_named_property(env, result, "icon", iconResult); } } + + // time?: number + napi_create_int32(env, capsule.GetTime(), &value); + napi_set_named_property(env, result, "time", value); + + // capsuleButton?: Array; + napi_value cardBtn = nullptr; + napi_create_array_with_length(env, capsule.GetCapsuleButton().size(), &cardBtn); + if (!SetCardButton(env, capsule.GetCapsuleButton(), cardBtn)) { + ANS_LOGE("capsuleButton call failed"); + return NapiGetBoolean(env, false); + } + napi_set_named_property(env, result, "capsuleButton", cardBtn); + return NapiGetBoolean(env, true); } @@ -221,7 +254,7 @@ napi_value Common::SetObjectUint32Property(const napi_env &env, napi_value& obje return NapiGetNull(env); } -napi_value Common::SetResourceObject(napi_env env, std::shared_ptr &resource, +napi_value Common::SetResourceObject(napi_env env, const std::shared_ptr &resource, napi_value &object) { if (SetObjectStringProperty(env, object, "bundleName", resource->bundleName) == nullptr) { @@ -297,6 +330,49 @@ napi_value Common::SetButton(const napi_env &env, const NotificationLocalLiveVie return NapiGetBoolean(env, true); } +napi_value Common::SetCardButton(const napi_env &env, const std::vector buttons, + napi_value &result) +{ + ANS_LOGD("enter"); + + int iconCount = 0; + napi_value value = nullptr; + for (auto btn : buttons) { + // name: string + napi_value item = nullptr; + napi_status status = napi_create_object(env, &item); + if (status != napi_ok) { + ANS_LOGE("Failed to create card button item"); + return NapiGetBoolean(env, false); + } + napi_create_string_utf8(env, btn.GetName().c_str(), NAPI_AUTO_LENGTH, &value); + napi_set_named_property(env, item, "name", value); + + // text?: string; + napi_create_string_utf8(env, btn.GetText().c_str(), NAPI_AUTO_LENGTH, &value); + napi_set_named_property(env, item, "text", value); + + // hidePanel?: boolean; + napi_get_boolean(env, btn.GetHidePanel(), &value); + napi_set_named_property(env, item, "hidePanel", value); + + // iconsResource: Resource; + napi_value object; + status = napi_create_object(env, &object); + if (status != napi_ok) { + ANS_LOGE("Failed to create card button item.resource"); + return NapiGetBoolean(env, false); + } + if (!SetResourceObject(env, btn.GetIconResource(), object)) { + return NapiGetBoolean(env, false); + } + napi_set_named_property(env, item, "iconsResource", object); + status = napi_set_element(env, result, iconCount, item); + iconCount++; + } + return NapiGetBoolean(env, true); +} + napi_value Common::SetNotificationLiveViewContent( const napi_env &env, NotificationBasicContent *basicContent, napi_value &result) { @@ -431,6 +507,7 @@ napi_value Common::GetNotificationLocalLiveViewCapsule( char str[STR_MAX_SIZE] = {0}; std::shared_ptr pixelMap = nullptr; napi_value result = nullptr; + int32_t intValue; ANS_LOGD("enter"); @@ -502,12 +579,180 @@ napi_value Common::GetNotificationLocalLiveViewCapsule( ANS_LOGD("capsule icon = %{public}d", pixelMap->GetWidth()); } + //time?: number + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "time", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "time", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument type. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &intValue); + capsule.SetTime(intValue); + } + + NAPI_CALL(env, napi_has_named_property(env, capsuleResult, "capsuleButton", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, capsuleResult, "capsuleButton", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + if (hasProperty && GetNotificationLocalLiveViewCapsuleCardButton(env, result, capsule) == nullptr) { + return nullptr; + } + } + content->SetCapsule(capsule); content->addFlag(NotificationLocalLiveViewContent::LiveViewContentInner::CAPSULE); return NapiGetNull(env); } +napi_value Common::GetNotificationLocalLiveViewCardButton( + const napi_env &env, const napi_value &contentResult, + std::shared_ptr content) +{ + napi_value buttonResult = nullptr; + + ANS_LOGD("enter"); + napi_get_named_property(env, contentResult, "cardButton", &buttonResult); + + // 解析iconbutton数组 + std::vector cardButtons; + if (GetNotificationIconButton(env, buttonResult, cardButtons) == nullptr) { + return nullptr; + } + + content->SetCardButton(cardButtons); + content->addFlag(NotificationLocalLiveViewContent::LiveViewContentInner::CARD_BUTTON); + return NapiGetNull(env); +} + +napi_value Common::GetNotificationLocalLiveViewCapsuleCardButton( + const napi_env &env, const napi_value &capsuletResult, + OHOS::Notification::NotificationCapsule &capsule) +{ + ANS_LOGD("enter"); + std::vector cardButtons; + if (GetNotificationIconButton(env, capsuletResult, cardButtons) == nullptr) { + return nullptr; + } + + capsule.SetCapsuleButton(cardButtons); + return NapiGetNull(env); +} + +napi_value Common::GetNotificationIconButton( + const napi_env &env, const napi_value &buttonResult, std::vector &cardButtons) +{ + // cardButton_item?: NotificationIconButton; + napi_value cardButton = nullptr; + napi_value result = nullptr; + napi_valuetype valuetype = napi_undefined; + + bool isArray = false; + bool boolValue = false; + uint32_t length = 0; + + size_t strLen = 0; + char str[STR_MAX_SIZE] = {0}; + bool hasProperty = false; + + ANS_LOGD("enter"); + napi_is_array(env, buttonResult, &isArray); + if (!isArray) { + ANS_LOGE("Property names is expected to be an array."); + return nullptr; + } + napi_get_array_length(env, buttonResult, &length); + if (length > BUTTON_MAX_SIZE) { + length = BUTTON_MAX_SIZE; + } + + for (size_t i = 0; i < length; i++) { + napi_get_element(env, buttonResult, i, &cardButton); + + NAPI_CALL(env, napi_typeof(env, cardButton, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. Object expected."); + return nullptr; + } + // 数组item + NotificationIconButton button; + // name: string + NAPI_CALL(env, napi_has_named_property(env, cardButton, "name", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property name expected."); + return nullptr; + } else { + napi_get_named_property(env, cardButton, "name", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + button.SetName(str); + } + + // iconsResource: Resource + NAPI_CALL(env, napi_has_named_property(env, cardButton, "iconsResource", &hasProperty)); + if (!hasProperty) { + ANS_LOGE("Property iconsResource expected."); + return nullptr; + } else { + napi_value iconResource = nullptr; + auto resource = std::make_shared(); + napi_get_named_property(env, cardButton, "iconsResource", &iconResource); + NAPI_CALL(env, napi_typeof(env, iconResource, &valuetype)); + if (valuetype != napi_object) { + ANS_LOGE("Wrong argument type. iconsResource Object expected."); + return nullptr; + } + if (Common::GetResourceObject(env, resource, iconResource) == nullptr) { + ANS_LOGW("Invalid icon resource object."); + return nullptr; + } else { + button.SetIconResource(resource); + } + } + + // text?: string + NAPI_CALL(env, napi_has_named_property(env, cardButton, "text", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, cardButton, "text", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_string) { + ANS_LOGE("Wrong argument type. String expected."); + return nullptr; + } + NAPI_CALL(env, napi_get_value_string_utf8(env, result, str, STR_MAX_SIZE - 1, &strLen)); + button.SetText(str); + } + + // hidePanel?: boolean; + NAPI_CALL(env, napi_has_named_property(env, cardButton, "hidePanel", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, cardButton, "hidePanel", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_boolean) { + ANS_LOGE("Wrong argument type. bool expected."); + return nullptr; + } + napi_get_value_bool(env, result, &boolValue); + button.SetHidePanel(boolValue); + } + + cardButtons.push_back(button); + ANS_LOGD("icon button = %{public}s", button.Dump().c_str()); + } + + return NapiGetNull(env); +} + napi_value Common::GetResourceObject(napi_env env, std::shared_ptr &resource, napi_value &value) { @@ -859,6 +1104,26 @@ napi_value Common::GetNotificationLocalLiveViewContentDetailed( return nullptr; } + //cardButton? + NAPI_CALL(env, napi_has_named_property(env, contentResult, "cardButton", &hasProperty)); + if (hasProperty && GetNotificationLocalLiveViewCardButton(env, contentResult, content) == nullptr) { + return nullptr; + } + + // liveViewType?: number + NAPI_CALL(env, napi_has_named_property(env, contentResult, "liveViewType", &hasProperty)); + if (hasProperty) { + napi_get_named_property(env, contentResult, "liveViewType", &result); + NAPI_CALL(env, napi_typeof(env, result, &valuetype)); + if (valuetype != napi_number) { + ANS_LOGE("Wrong argument liveViewType. Number expected."); + return nullptr; + } + napi_get_value_int32(env, result, &type); + content->SetLiveviewType(type); + ANS_LOGD("localLiveView SetLiveviewType = %{public}d", type); + } + //progress? NAPI_CALL(env, napi_has_named_property(env, contentResult, "progress", &hasProperty)); if (hasProperty && GetNotificationLocalLiveViewProgress(env, contentResult, content) == nullptr) { diff --git a/interfaces/inner_api/notification_capsule.h b/interfaces/inner_api/notification_capsule.h index 65ef26aa5618b0f9955bf9e385758785da23d954..6b3f6de30d0dd09f15fbbf60515fdff3f67f0f87 100644 --- a/interfaces/inner_api/notification_capsule.h +++ b/interfaces/inner_api/notification_capsule.h @@ -19,6 +19,7 @@ #include "pixel_map.h" #include "notification_json_convert.h" #include "parcel.h" +#include "notification_icon_button.h" #include namespace OHOS { @@ -65,6 +66,24 @@ public: void SetContent(const std::string &content); + /** + * @brief Obtains the button of the notification capsule. + * + * @return Returns the button of the notification capsule. + */ + std::vector GetCapsuleButton() const; + + void SetCapsuleButton(const std::vector &buttons); + + /** + * @brief Obtains the expire time of the notification capsule. + * + * @return Returns the expire time of the notification capsule. + */ + int32_t GetTime() const; + + void SetTime(int32_t time); + /** * @brief Returns a string representation of the object. * @@ -120,6 +139,8 @@ private: std::string backgroundColor_ {}; std::string content_ {}; std::shared_ptr icon_ {}; + std::vector capsuleButton_; + int32_t time_ {-1}; }; } // namespace Notification } // namespace OHOS diff --git a/interfaces/inner_api/notification_icon_button.h b/interfaces/inner_api/notification_icon_button.h new file mode 100644 index 0000000000000000000000000000000000000000..e95d07fa43de617b9ae0cca51a4e6fd85b7866b7 --- /dev/null +++ b/interfaces/inner_api/notification_icon_button.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_INTERFACES_INNER_API_ICON_BUTTON_H +#define BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_INTERFACES_INNER_API_ICON_BUTTON_H + +#include "notification_json_convert.h" +#include "resource_manager.h" +#include "parcel.h" +#include +#include + +namespace OHOS { +namespace Notification { +using namespace Global::Resource; +const uint32_t BUTTON_MAX_SIZE = 3; +const uint32_t BUTTON_RESOURCE_SIZE = 3; +const uint32_t RESOURCE_BUNDLENAME_INDEX = 0; +const uint32_t RESOURCE_MODULENAME_INDEX = 1; +const uint32_t RESOURCE_ID_INDEX = 2; + +class NotificationIconButton : public Parcelable, public NotificationJsonConvertionBase { +public: + NotificationIconButton() = default; + ~NotificationIconButton() = default; + /** + * @brief Obtains the icon of the notification capsule. + * + * @return Returns the icon of the notification capsule. + */ + const std::shared_ptr GetIconResource() const; + + void SetIconResource(const std::shared_ptr &iconResource); + + /** + * @brief Obtains the text of the notification button. + * + * @return Returns the text of the notification button. + */ + std::string GetText() const; + + void SetText(const std::string &text); + + /** + * @brief Obtains the unqiue name of the notification button. + * + * @return Returns the unqiue name of the notification button. + */ + std::string GetName() const; + + void SetName(const std::string &name); + + /** + * @brief Obtains the hidePanel of the notification button. + * + * @return Returns the hidePanel of the notification button. + */ + bool GetHidePanel() const; + + void SetHidePanel(bool hidePanel); + + /** + * @brief Returns a string representation of the object. + * + * @return Returns a string representation of the object. + */ + std::string Dump(); + + /** + * @brief Converts a notification capsule object into a Json. + * + * @param jsonObject Indicates the Json object. + * @return Returns true if succeed; returns false otherwise. + */ + bool ToJson(nlohmann::json &jsonObject) const override; + + /** + * @brief Creates a notification capsule object from a Json. + * + * @param jsonObject Indicates the Json object. + * @return Returns the notification capsule. + */ + static NotificationIconButton *FromJson(const nlohmann::json &jsonObject); + + /** + * @brief Marshal a object into a Parcel. + * + * @param parcel Indicates the object into the parcel. + * @return Returns true if succeed; returns false otherwise. + */ + virtual bool Marshalling(Parcel &parcel) const override; + + /** + * @brief Unmarshal object from a Parcel. + * + * @param parcel Indicates the parcel object. + * @return Returns the notification capsule. + */ + static NotificationIconButton *Unmarshalling(Parcel &parcel); + + void ClearButtonIconsResource(); +private: + + /** + * @brief Read a NotificationConversationalMessage object from a Parcel. + * + * @param parcel Indicates the parcel object. + * @return Returns true if succeed; returns false otherwise. + */ + bool ReadFromParcel(Parcel &parcel); + static bool ResourceFromJson(const nlohmann::json &resource, + std::shared_ptr& resourceObj); +private: + std::string text_ {}; + std::string name_ {}; + std::shared_ptr iconResource_ {}; + bool hidePanel_; +}; +} // namespace Notification +} // namespace OHOS +#endif //BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_INTERFACES_INNER_API_ICON_BUTTON_H \ No newline at end of file diff --git a/interfaces/inner_api/notification_local_live_view_content.h b/interfaces/inner_api/notification_local_live_view_content.h index 6792ac58e2cfd22d7632c181dc44dfda045b45c1..ec620c39187a3d68d2ed0338c5576e929ff43752 100644 --- a/interfaces/inner_api/notification_local_live_view_content.h +++ b/interfaces/inner_api/notification_local_live_view_content.h @@ -26,6 +26,7 @@ #include "notification_time.h" #include "parcel.h" #include +#include "ans_const_define.h" namespace OHOS { namespace Notification { @@ -37,6 +38,7 @@ public: PROGRESS, TIME, INITIAL_TIME, + CARD_BUTTON, }; NotificationLocalLiveViewContent() = default; @@ -81,6 +83,19 @@ public: */ NotificationLocalLiveViewButton GetButton(); + /* + * @brief Sets the card button to be included in a local live view notification. + * + * @param button Indicates the type to be included. + */ + void SetCardButton(std::vector buttons); + + /* + * @brief Get the card button of a local live view notification. + * + */ + std::vector GetCardButton(); + /* * @brief Sets the progress to be included in a local live view notification. * @@ -121,6 +136,19 @@ public: */ bool isFlagExist(int32_t flag); + /* + * @brief Sets the type to be included in a local live view notification. + * + * @param type Indicates the type to be included. + */ + void SetLiveviewType(int32_t type); + + /* + * @brief Get the type of a local live view notification. + * + */ + int32_t GetLiveviewType(); + /** * @brief Returns a string representation of the object. * @@ -177,9 +205,11 @@ private: int32_t type_ {0}; NotificationCapsule capsule_ {}; NotificationLocalLiveViewButton button_ {}; + std::vector card_button_ {}; NotificationProgress progress_ {}; NotificationTime time_ {}; std::vector flags_ {}; + int32_t liveviewType_ {-1}; }; } // namespace Notification } // namespace OHOS diff --git a/services/ans/BUILD.gn b/services/ans/BUILD.gn index c44e54ab6d2539c97e5c9d180966767353d5eb77..fb6bec30983e6b4b3d6eeff9a383ac6844bcdab7 100644 --- a/services/ans/BUILD.gn +++ b/services/ans/BUILD.gn @@ -58,6 +58,7 @@ ohos_source_set("ans_service_sources") { "src/advanced_datashare_observer.cpp", "src/advanced_notification_clone_service.cpp", "src/advanced_notification_event_service.cpp", + "src/advanced_notification_flow_control_service.cpp", "src/advanced_notification_inline.cpp", "src/advanced_notification_live_view_service.cpp", "src/advanced_notification_publish/base_publish_process.cpp", diff --git a/services/ans/include/advanced_notification_flow_control_service.h b/services/ans/include/advanced_notification_flow_control_service.h new file mode 100644 index 0000000000000000000000000000000000000000..cb182f8174f8ce3b49c9d8a75cdf29945f9b5ef4 --- /dev/null +++ b/services/ans/include/advanced_notification_flow_control_service.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_SERVICES_ANS_INCLUDE_NOTIFICATION_FLOW_CONTROL_SERVICE_H +#define BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_SERVICES_ANS_INCLUDE_NOTIFICATION_FLOW_CONTROL_SERVICE_H + +#include +#include +#include +#include + +#include "errors.h" +#include "singleton.h" +#include "ans_const_define.h" +#include "notification_record.h" + +namespace OHOS { +namespace Notification { +struct FlowControlThreshold { + uint32_t maxCreateNumPerSecond = MAX_CREATE_NUM_PERSECOND; + uint32_t maxUpdateNumPerSecond = MAX_UPDATE_NUM_PERSECOND; + uint32_t maxCreateNumPerSecondPerApp = MAX_CREATE_NUM_PERSECOND_PERAPP; + uint32_t maxUpdateNumPerSecondPerApp = MAX_UPDATE_NUM_PERSECOND_PERAPP; +}; + +class FlowControlService : public DelayedSingleton { +public: + FlowControlService(); + ErrCode FlowControl(const std::shared_ptr &record, + const int32_t callingUid, bool isNotificationExists); + +private: + ErrCode PublishFlowCtrl(const std::shared_ptr &record, const int32_t callingUid); + ErrCode PublishGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now); + ErrCode PublishSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void PublishRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now); + + ErrCode UpdateFlowCtrl(const std::shared_ptr &record, const int32_t callingUid); + ErrCode UpdateGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now); + ErrCode UpdateSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void UpdateRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now); + +private: + static std::mutex flowControlMutex_; + std::list flowControlUpdateTimestampList_; + std::list flowControlPublishTimestampList_; + static std::mutex systemFlowControlMutex_; + std::list systemFlowControlUpdateTimestampList_; + std::list systemFlowControlPublishTimestampList_; + static std::mutex singleAppFlowControlMutex_; + std::map>> singleAppFlowControlUpdateTimestampMap_; + std::map>> singleAppFlowControlPublishTimestampMap_; + + FlowControlThreshold threshold_; +}; +} // namespace Notification +} // namespace OHOS + +#endif // BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_SERVICES_ANS_INCLUDE_NOTIFICATION_FLOW_CONTROL_SERVICE_H \ No newline at end of file diff --git a/services/ans/include/advanced_notification_service.h b/services/ans/include/advanced_notification_service.h index d84de77f65c65f697d6ec1b90eb0ed5631573a62..4ab70ae47d042d35f06f9d604efe6465e404e2b3 100644 --- a/services/ans/include/advanced_notification_service.h +++ b/services/ans/include/advanced_notification_service.h @@ -1214,7 +1214,6 @@ private: void SortNotificationList(); static bool NotificationCompare( const std::shared_ptr &first, const std::shared_ptr &second); - ErrCode FlowControl(const std::shared_ptr &record, const int32_t callingUid); ErrCode PublishInNotificationList(const std::shared_ptr &record); ErrCode RemoveNotificationBySlot(const sptr &bundleOption, const sptr &slot, const int reason); @@ -1404,19 +1403,6 @@ private: ErrCode CheckNeedSilent(const std::string &phoneNumber, int32_t callerType, int32_t userId); uint32_t GetDefaultSlotFlags(const sptr &request); bool IsSystemUser(int32_t userId); - ErrCode UpdateFlowCtrl(const std::shared_ptr &record, const int32_t callingUid); - ErrCode UpdateGlobalFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now); - ErrCode UpdateSingleAppFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now, const int32_t callingUid); - void UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now); - ErrCode PublishFlowCtrl(const std::shared_ptr &record, const int32_t callingUid); - ErrCode PublishGlobalFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now); - ErrCode PublishSingleAppFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now, const int32_t callingUid); - void PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now); - void GetFlowCtrlConfigFromCCM(); ErrCode SetEnabledForBundleSlotInner(const sptr &bundleOption, const sptr &bundle, const NotificationConstant::SlotType &slotType, bool enabled, bool isForceControl); @@ -1438,21 +1424,6 @@ private: std::shared_ptr runner_ = nullptr; std::shared_ptr handler_ = nullptr; std::list> notificationList_; - static std::mutex flowControlMutex_; - std::list flowControlUpdateTimestampList_; - std::list flowControlPublishTimestampList_; - static std::mutex systemFlowControlMutex_; - std::list systemFlowControlUpdateTimestampList_; - std::list systemFlowControlPublishTimestampList_; - static std::mutex singleAppFlowControlMutex_; - std::map>> singleAppFlowControlUpdateTimestampMap_; - std::map>> singleAppFlowControlPublishTimestampMap_; - uint32_t maxCreateNumPerSecond = MAX_CREATE_NUM_PERSECOND; - uint32_t maxUpdateNumPerSecond = MAX_UPDATE_NUM_PERSECOND; - uint32_t maxCreateNumPerSecondPerApp = MAX_CREATE_NUM_PERSECOND_PERAPP; - uint32_t maxUpdateNumPerSecondPerApp = MAX_UPDATE_NUM_PERSECOND_PERAPP; std::shared_ptr recentInfo_ = nullptr; std::shared_ptr distributedKvStoreDeathRecipient_ = nullptr; std::shared_ptr systemEventObserver_ = nullptr; diff --git a/services/ans/include/notification_config_parse.h b/services/ans/include/notification_config_parse.h index cd1ef282f9795f71b1168f0dcfb8fc6ee6a15dec..8408fdced4ca05d298367fc4ba76cbbefc95ce4d 100644 --- a/services/ans/include/notification_config_parse.h +++ b/services/ans/include/notification_config_parse.h @@ -29,6 +29,7 @@ #include "notification_bundle_option.h" #include "notification_constant.h" #include "notification_flags.h" +#include "advanced_notification_flow_control_service.h" namespace OHOS { namespace Notification { @@ -45,7 +46,8 @@ public: bool IsLiveViewEnabled(const std::string bundleName) const; bool IsBannerEnabled(const std::string bundleName) const; bool IsReminderEnabled(const std::string& bundleName) const; - + void GetFlowCtrlConfigFromCCM(FlowControlThreshold &threshold); + private: std::map defaultCurrentSlotReminder_; std::vector notificationConfigJsons_; diff --git a/services/ans/src/advanced_notification_flow_control_service.cpp b/services/ans/src/advanced_notification_flow_control_service.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c47d90bffaa4549f208638aa15e9caa80ef04b0 --- /dev/null +++ b/services/ans/src/advanced_notification_flow_control_service.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "advanced_notification_flow_control_service.h" + +#include "ans_inner_errors.h" +#include "notification_config_parse.h" +#include "notification_analytics_util.h" + +namespace OHOS { +namespace Notification { +std::mutex FlowControlService::flowControlMutex_; +std::mutex FlowControlService::systemFlowControlMutex_; +std::mutex FlowControlService::singleAppFlowControlMutex_; + +FlowControlService::FlowControlService() +{ + DelayedSingleton::GetInstance()->GetFlowCtrlConfigFromCCM(threshold_); +} + +ErrCode FlowControlService::FlowControl(const std::shared_ptr &record, + const int32_t callingUid, bool isNotificationExists) +{ + if (record->isNeedFlowCtrl == false) { + return ERR_OK; + } + + ErrCode result = ERR_OK; + if (!isNotificationExists) { + if (record->request->IsUpdateOnly()) { + ANS_LOGW("Notification not exists when update"); + return ERR_ANS_NOTIFICATION_NOT_EXISTS; + } + result = PublishFlowCtrl(record, callingUid); + } else { + result = UpdateFlowCtrl(record, callingUid); + } + + return result; +} + +ErrCode FlowControlService::PublishFlowCtrl(const std::shared_ptr &record, + const int32_t callingUid) +{ + if (record->isNeedFlowCtrl == false) { + return ERR_OK; + } + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + ErrCode result = ERR_OK; + result = PublishSingleAppFlowCtrl(record, now, callingUid); + if (result != ERR_OK) { + return result; + } + result = PublishGlobalFlowCtrl(record, now); + if (result != ERR_OK) { + return result; + } + PublishRecordTimestamp(record, now, callingUid); + PublishSingleAppFlowCtrlRemoveExpire(now); + return ERR_OK; +} + +ErrCode FlowControlService::PublishGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now) +{ + ANS_LOGD("PublishGlobalFlowCtrl size %{public}zu,%{public}zu", + flowControlPublishTimestampList_.size(), systemFlowControlPublishTimestampList_.size()); + if (record->isThirdparty == true) { + // Third-part flow control + std::lock_guard lock(flowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(flowControlPublishTimestampList_, now); + if (flowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) { + ANS_LOGE("Third-part PublishGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_2) + .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("Third-part PublishGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; + } + } else { + // System flow control + std::lock_guard lock(systemFlowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(systemFlowControlPublishTimestampList_, now); + if (systemFlowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) { + ANS_LOGE("System PublishGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_3) + .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("System PublishGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; + } + } + return ERR_OK; +} + +ErrCode FlowControlService::PublishSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) { + return ERR_OK; + } + NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now); + if (singleAppFlowControlIter->second->size() >= threshold_.maxCreateNumPerSecondPerApp) { + ANS_LOGE("SingleAppPublishFlowControl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_4) + .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("SingleAppPublishFlowControl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; + } + return ERR_OK; +} + +void FlowControlService::PublishRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + if (record->isThirdparty == true) { + std::lock_guard lock(flowControlMutex_); + flowControlPublishTimestampList_.push_back(now); + } else { + std::lock_guard lock(systemFlowControlMutex_); + systemFlowControlPublishTimestampList_.push_back(now); + } + + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) { + singleAppFlowControlPublishTimestampMap_[callingUid] = + std::make_shared>(); + singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); + } + singleAppFlowControlIter->second->push_back(now); +} + +void FlowControlService::PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + for (auto iter = singleAppFlowControlPublishTimestampMap_.begin(); + iter != singleAppFlowControlPublishTimestampMap_.end();) { + auto latest = iter->second->back(); + if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) { + iter = singleAppFlowControlPublishTimestampMap_.erase(iter); + } else { + ++iter; + } + } +} + +ErrCode FlowControlService::UpdateFlowCtrl(const std::shared_ptr &record, + const int32_t callingUid) +{ + if (record->isNeedFlowCtrl == false) { + return ERR_OK; + } + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + ErrCode result = ERR_OK; + result = UpdateSingleAppFlowCtrl(record, now, callingUid); + if (result != ERR_OK) { + return result; + } + result = UpdateGlobalFlowCtrl(record, now); + if (result != ERR_OK) { + return result; + } + UpdateRecordTimestamp(record, now, callingUid); + UpdateSingleAppFlowCtrlRemoveExpire(now); + return result; +} + +ErrCode FlowControlService::UpdateGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now) +{ + ANS_LOGD("UpdateGlobalFlowCtrl size %{public}zu,%{public}zu", + flowControlUpdateTimestampList_.size(), systemFlowControlUpdateTimestampList_.size()); + if (record->isThirdparty == true) { + // Third-part flow control + std::lock_guard lock(flowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(flowControlUpdateTimestampList_, now); + if (flowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) { + ANS_LOGE("Third-part UpdateGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_3) + .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("Third-part updateGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; + } + } else { + // System flow control + std::lock_guard lock(systemFlowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(systemFlowControlUpdateTimestampList_, now); + if (systemFlowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) { + ANS_LOGE("System UpdateGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_4) + .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("System updateGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; + } + } + return ERR_OK; +} + +ErrCode FlowControlService::UpdateSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) { + return ERR_OK; + } + NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now); + if (singleAppFlowControlIter->second->size() >= threshold_.maxUpdateNumPerSecondPerApp) { + ANS_LOGE("SingleAppUpdateFlowControl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_5) + .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("SingleAppUpdateFlowControl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; + } + return ERR_OK; +} + +void FlowControlService::UpdateRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + if (record->isThirdparty == true) { + std::lock_guard lock(flowControlMutex_); + flowControlUpdateTimestampList_.push_back(now); + } else { + std::lock_guard lock(systemFlowControlMutex_); + systemFlowControlUpdateTimestampList_.push_back(now); + } + + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) { + singleAppFlowControlUpdateTimestampMap_[callingUid] = + std::make_shared>(); + singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); + } + singleAppFlowControlIter->second->push_back(now); +} + +void FlowControlService::UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + for (auto iter = singleAppFlowControlUpdateTimestampMap_.begin(); + iter != singleAppFlowControlUpdateTimestampMap_.end();) { + auto latest = iter->second->back(); + if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) { + iter = singleAppFlowControlUpdateTimestampMap_.erase(iter); + } else { + ++iter; + } + } +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/services/ans/src/advanced_notification_publish_service.cpp b/services/ans/src/advanced_notification_publish_service.cpp index 8b3e6432003e9f51f8ca84a76cc10197d931f615..b79f7d32c9973716eadde2ebbc0490661737ee5e 100644 --- a/services/ans/src/advanced_notification_publish_service.cpp +++ b/services/ans/src/advanced_notification_publish_service.cpp @@ -51,6 +51,7 @@ #include "if_system_ability_manager.h" #include "iservice_registry.h" #include "datashare_predicates.h" +#include "advanced_notification_flow_control_service.h" namespace OHOS { namespace Notification { @@ -235,7 +236,8 @@ ErrCode AdvancedNotificationService::PublishNotificationForIndirectProxy(const s return; } - result = FlowControl(record, ipcUid); + bool isNotificationExists = IsNotificationExists(record->notification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, ipcUid, isNotificationExists); if (result != ERR_OK) { return; } @@ -2305,7 +2307,8 @@ ErrCode AdvancedNotificationService::PublishNotificationBySa(const sptrnotification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, ipcUid, isNotificationExists); if (result != ERR_OK) { return; } diff --git a/services/ans/src/advanced_notification_service.cpp b/services/ans/src/advanced_notification_service.cpp index 93520accf67b4c723c914d542d2282f795ec7b86..6213f050dcdf5402dd389c5d172548a5263ff545 100644 --- a/services/ans/src/advanced_notification_service.cpp +++ b/services/ans/src/advanced_notification_service.cpp @@ -74,6 +74,7 @@ #include "advanced_notification_inline.cpp" #include "advanced_datashare_helper_ext.h" #include "notification_analytics_util.h" +#include "advanced_notification_flow_control_service.h" namespace OHOS { namespace Notification { @@ -98,9 +99,6 @@ constexpr const char *KEY_UNIFIED_GROUP_ENABLE = "unified_group_enable"; sptr AdvancedNotificationService::instance_; std::mutex AdvancedNotificationService::instanceMutex_; std::mutex AdvancedNotificationService::pushMutex_; -std::mutex AdvancedNotificationService::flowControlMutex_; -std::mutex AdvancedNotificationService::systemFlowControlMutex_; -std::mutex AdvancedNotificationService::singleAppFlowControlMutex_; std::mutex AdvancedNotificationService::doNotDisturbMutex_; std::map slotFlagsDefaultMap_; @@ -333,7 +331,6 @@ AdvancedNotificationService::AdvancedNotificationService() systemEventObserver_ = std::make_shared(iSystemEvent); dataManager_.RegisterKvStoreServiceDeathRecipient(distributedKvStoreDeathRecipient_); - GetFlowCtrlConfigFromCCM(); #ifdef DISTRIBUTED_NOTIFICATION_SUPPORTED InitDistributeCallBack(); #endif @@ -368,10 +365,7 @@ ErrCode AdvancedNotificationService::AssignToNotificationList(const std::shared_ ErrCode result = ERR_OK; if (!IsNotificationExists(record->notification->GetKey())) { if (record->request->IsUpdateOnly()) { - ANS_LOGE("Notification not exists when update"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_3) - .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("Nft not exist"); - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + ANS_LOGW("Notification not exists when update"); return ERR_ANS_NOTIFICATION_NOT_EXISTS; } record->request->SetCreateTime(GetCurrentTime()); @@ -680,7 +674,8 @@ ErrCode AdvancedNotificationService::PublishPreparedNotification(const sptrnotification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, uid, isNotificationExists); if (result != ERR_OK) { return; } @@ -1009,114 +1004,6 @@ void AdvancedNotificationService::AddToNotificationList(const std::shared_ptr &record, const int32_t callingUid) -{ - if (record->isNeedFlowCtrl == false) { - return ERR_OK; - } - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - ErrCode result = ERR_OK; - result = UpdateSingleAppFlowCtrl(record, now, callingUid); - if (result != ERR_OK) { - return result; - } - result = UpdateGlobalFlowCtrl(record, now); - if (result != ERR_OK) { - return result; - } - if (record->isThirdparty == true) { - std::lock_guard lock(flowControlMutex_); - flowControlUpdateTimestampList_.push_back(now); - } else { - std::lock_guard lock(systemFlowControlMutex_); - systemFlowControlUpdateTimestampList_.push_back(now); - } - - { - std::lock_guard lock(singleAppFlowControlMutex_); - auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); - if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) { - singleAppFlowControlUpdateTimestampMap_[callingUid] = - std::make_shared>(); - singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); - } - singleAppFlowControlIter->second->push_back(now); - } - - UpdateSingleAppFlowCtrlRemoveExpire(now); - return result; -} - -ErrCode AdvancedNotificationService::UpdateGlobalFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now) -{ - ANS_LOGD("UpdateGlobalFlowCtrl size %{public}zu,%{public}zu", - flowControlUpdateTimestampList_.size(), systemFlowControlUpdateTimestampList_.size()); - if (record->isThirdparty == true) { - // 三方流控 - std::lock_guard lock(flowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(flowControlUpdateTimestampList_, now); - if (flowControlUpdateTimestampList_.size() >= maxUpdateNumPerSecond) { - ANS_LOGE("Third-part UpdateGlobalFlowCtrl failed"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_4) - .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("UpdateGlobalFlowCtrl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; - } - } else { - // 系统流控 - std::lock_guard lock(systemFlowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(systemFlowControlUpdateTimestampList_, now); - if (systemFlowControlUpdateTimestampList_.size() >= maxUpdateNumPerSecond) { - ANS_LOGE("System UpdateGlobalFlowCtrl failed"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_4) - .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("UpdateGlobalFlowCtrl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; - } - } - return ERR_OK; -} - -ErrCode AdvancedNotificationService::UpdateSingleAppFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now, const int32_t callingUid) -{ - std::lock_guard lock(singleAppFlowControlMutex_); - auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); - if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) { - return ERR_OK; - } - NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now); - if (singleAppFlowControlIter->second->size() >= maxUpdateNumPerSecondPerApp) { - ANS_LOGE("SingleAppUpdateFlowControl failed"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_6) - .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("SingleAppUpdateFlowControl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; - } - return ERR_OK; -} - -void AdvancedNotificationService::UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now) -{ - std::lock_guard lock(singleAppFlowControlMutex_); - for (auto iter = singleAppFlowControlUpdateTimestampMap_.begin(); - iter != singleAppFlowControlUpdateTimestampMap_.end();) { - auto latest = iter->second->back(); - if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) { - iter = singleAppFlowControlUpdateTimestampMap_.erase(iter); - } else { - ++iter; - } - } -} - ErrCode AdvancedNotificationService::UpdateInNotificationList(const std::shared_ptr &record) { auto iter = notificationList_.begin(); @@ -1592,146 +1479,11 @@ static bool SortNotificationsByLevelAndTime( return (first->slot->GetLevel() < second->slot->GetLevel()); } -ErrCode AdvancedNotificationService::FlowControl(const std::shared_ptr &record, - const int32_t callingUid) -{ - if (record->isNeedFlowCtrl == false) { - return ERR_OK; - } - - ErrCode result = ERR_OK; - if (!IsNotificationExists(record->notification->GetKey())) { - if (record->request->IsUpdateOnly()) { - ANS_LOGE("Notification not exists when update"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_3) - .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("Nft not exist"); - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - return ERR_ANS_NOTIFICATION_NOT_EXISTS; - } - result = PublishFlowCtrl(record, callingUid); - } else { - if (record->request->IsAlertOneTime()) { - CloseAlert(record); - } - result = UpdateFlowCtrl(record, callingUid); - } - - return result; -} - bool AdvancedNotificationService::IsSystemUser(int32_t userId) { return ((userId >= SUBSCRIBE_USER_SYSTEM_BEGIN) && (userId <= SUBSCRIBE_USER_SYSTEM_END)); } -ErrCode AdvancedNotificationService::PublishFlowCtrl(const std::shared_ptr &record, - const int32_t callingUid) -{ - if (record->isNeedFlowCtrl == false) { - return ERR_OK; - } - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - ErrCode result = ERR_OK; - result = PublishSingleAppFlowCtrl(record, now, callingUid); - if (result != ERR_OK) { - return result; - } - result = PublishGlobalFlowCtrl(record, now); - if (result != ERR_OK) { - return result; - } - if (record->isThirdparty == true) { - std::lock_guard lock(flowControlMutex_); - flowControlPublishTimestampList_.push_back(now); - } else { - std::lock_guard lock(systemFlowControlMutex_); - systemFlowControlPublishTimestampList_.push_back(now); - } - - { - std::lock_guard lock(singleAppFlowControlMutex_); - auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); - if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) { - singleAppFlowControlPublishTimestampMap_[callingUid] = - std::make_shared>(); - singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); - } - singleAppFlowControlIter->second->push_back(now); - } - PublishSingleAppFlowCtrlRemoveExpire(now); - return ERR_OK; -} - -ErrCode AdvancedNotificationService::PublishGlobalFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now) -{ - ANS_LOGD("PublishGlobalFlowCtrl size %{public}zu,%{public}zu", - flowControlPublishTimestampList_.size(), systemFlowControlPublishTimestampList_.size()); - if (record->isThirdparty == true) { - // 三方流控 - std::lock_guard lock(flowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(flowControlPublishTimestampList_, now); - if (flowControlPublishTimestampList_.size() >= maxCreateNumPerSecond) { - ANS_LOGE("Third-part PublishGlobalFlowCtrl failed"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_3) - .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("PublishGlobalFlowCtrl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; - } - } else { - // 系统流控 - std::lock_guard lock(systemFlowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(systemFlowControlPublishTimestampList_, now); - if (systemFlowControlPublishTimestampList_.size() >= maxCreateNumPerSecond) { - ANS_LOGE("System PublishGlobalFlowCtrl failed"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_3) - .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("PublishGlobalFlowCtrl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; - } - } - return ERR_OK; -} - -ErrCode AdvancedNotificationService::PublishSingleAppFlowCtrl(const std::shared_ptr &record, - std::chrono::system_clock::time_point now, const int32_t callingUid) -{ - std::lock_guard lock(singleAppFlowControlMutex_); - auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); - if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) { - return ERR_OK; - } - NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now); - if (singleAppFlowControlIter->second->size() >= maxCreateNumPerSecondPerApp) { - ANS_LOGE("SingleAppPublishFlowControl failed"); - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_6) - .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("SingleAppPublishFlowControl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; - } - return ERR_OK; -} - -void AdvancedNotificationService::PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now) -{ - std::lock_guard lock(singleAppFlowControlMutex_); - for (auto iter = singleAppFlowControlPublishTimestampMap_.begin(); - iter != singleAppFlowControlPublishTimestampMap_.end();) { - auto latest = iter->second->back(); - if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) { - iter = singleAppFlowControlPublishTimestampMap_.erase(iter); - } else { - ++iter; - } - } -} - ErrCode AdvancedNotificationService::PublishInNotificationList(const std::shared_ptr &record) { std::list> bundleList; @@ -2520,42 +2272,5 @@ void AdvancedNotificationService::RemoveNotificationList(const std::shared_ptrGetConfigJson(JsonPoint, root)) { - ANS_LOGE("Failed to get JsonPoint CCM config file"); - return; - } - if (!root.contains(NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE)) { - ANS_LOGW("GetFlowCtrlConfigFromCCM not found jsonKey"); - return; - } - nlohmann::json affects = root[NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE]; - if (affects.is_null() || affects.empty()) { - ANS_LOGE("GetFlowCtrlConfigFromCCM failed as invalid ccmFlowCtrlConfig json"); - return; - } - if (affects.contains(NotificationConfigParse::CFG_KEY_MAX_CREATE_NUM_PERSECOND)) { - maxCreateNumPerSecond = affects[NotificationConfigParse::CFG_KEY_MAX_CREATE_NUM_PERSECOND]; - } - - if (affects.contains(NotificationConfigParse::CFG_KEY_MAX_UPDATE_NUM_PERSECOND)) { - maxUpdateNumPerSecond = affects[NotificationConfigParse::CFG_KEY_MAX_UPDATE_NUM_PERSECOND]; - } - - if (affects.contains(NotificationConfigParse::CFG_KEY_MAX_CREATE_NUM_PERSECOND_PERAPP)) { - maxCreateNumPerSecondPerApp = affects[NotificationConfigParse::CFG_KEY_MAX_CREATE_NUM_PERSECOND_PERAPP]; - } - - if (affects.contains(NotificationConfigParse::CFG_KEY_MAX_UPDATE_NUM_PERSECOND_PERAPP)) { - maxUpdateNumPerSecondPerApp = affects[NotificationConfigParse::CFG_KEY_MAX_UPDATE_NUM_PERSECOND_PERAPP]; - } - - ANS_LOGI("GetFlowCtrlConfigFromCCM success"); -} } // namespace Notification } // namespace OHOS diff --git a/services/ans/src/advanced_notification_utils.cpp b/services/ans/src/advanced_notification_utils.cpp index b04eb25303a105d8ea238264b8168294e5fe86ba..71cfdb878391faf2c6d3f958026b26c14fddd0d5 100644 --- a/services/ans/src/advanced_notification_utils.cpp +++ b/services/ans/src/advanced_notification_utils.cpp @@ -51,6 +51,7 @@ #include "notification_analytics_util.h" #include "notification_clone_disturb_service.h" #include "notification_clone_bundle_service.h" +#include "advanced_notification_flow_control_service.h" #define CHECK_BUNDLE_OPTION_IS_INVALID(option) \ if (option == nullptr || option->GetBundleName().empty()) { \ @@ -995,7 +996,8 @@ void AdvancedNotificationService::OnDistributedPublish( return; } - result = FlowControl(record, callingUid); + bool isNotificationExists = IsNotificationExists(record->notification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, isNotificationExists); if (result != ERR_OK) { return; } @@ -1024,7 +1026,8 @@ void AdvancedNotificationService::OnDistributedUpdate( ANS_LOGE("Serial queue is invalid."); return; } - notificationSvrQueue_->submit(std::bind([this, deviceId, bundleName, request, activeUserId]() { + const int32_t callingUid = IPCSkeleton::GetCallingUid(); + notificationSvrQueue_->submit(std::bind([this, deviceId, bundleName, request, activeUserId, callingUid]() { ANS_LOGD("ffrt enter!"); if (!CheckDistributedNotificationType(request)) { ANS_LOGD("device type not support display."); @@ -1072,7 +1075,11 @@ void AdvancedNotificationService::OnDistributedUpdate( ANS_LOGE("Reject by filters: %{public}d", result); return; } - + bool isNotificationExists = IsNotificationExists(record->notification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, isNotificationExists); + if (result != ERR_OK) { + return; + } if (IsNotificationExists(record->notification->GetKey())) { if (record->request->IsAlertOneTime()) { CloseAlert(record); diff --git a/services/ans/src/common/notification_config_parse.cpp b/services/ans/src/common/notification_config_parse.cpp index 685e90bebad016bdb8d44cf694310c8f8e6899da..c69ed056e764d626f641ecc1f9ef4959fe6db1d6 100644 --- a/services/ans/src/common/notification_config_parse.cpp +++ b/services/ans/src/common/notification_config_parse.cpp @@ -195,5 +195,42 @@ bool NotificationConfigParse::IsBannerEnabled(const std::string bundleName) cons return false; #endif } + +void NotificationConfigParse::GetFlowCtrlConfigFromCCM(FlowControlThreshold &threshold) +{ + nlohmann::json root; + std::string JsonPoint = "/"; + JsonPoint.append(CFG_KEY_NOTIFICATION_SERVICE); + if (!GetConfigJson(JsonPoint, root)) { + ANS_LOGE("Failed to get JsonPoint CCM config file"); + return; + } + if (!root.contains(CFG_KEY_NOTIFICATION_SERVICE)) { + ANS_LOGW("GetFlowCtrlConfigFromCCM not found jsonKey"); + return; + } + nlohmann::json affects = root[CFG_KEY_NOTIFICATION_SERVICE]; + if (affects.is_null() || affects.empty()) { + ANS_LOGE("GetFlowCtrlConfigFromCCM failed as invalid ccmFlowCtrlConfig json"); + return; + } + if (affects.contains(CFG_KEY_MAX_CREATE_NUM_PERSECOND)) { + threshold.maxCreateNumPerSecond = affects[CFG_KEY_MAX_CREATE_NUM_PERSECOND]; + } + + if (affects.contains(CFG_KEY_MAX_UPDATE_NUM_PERSECOND)) { + threshold.maxUpdateNumPerSecond = affects[CFG_KEY_MAX_UPDATE_NUM_PERSECOND]; + } + + if (affects.contains(CFG_KEY_MAX_CREATE_NUM_PERSECOND_PERAPP)) { + threshold.maxCreateNumPerSecondPerApp = affects[CFG_KEY_MAX_CREATE_NUM_PERSECOND_PERAPP]; + } + + if (affects.contains(CFG_KEY_MAX_UPDATE_NUM_PERSECOND_PERAPP)) { + threshold.maxUpdateNumPerSecondPerApp = affects[CFG_KEY_MAX_UPDATE_NUM_PERSECOND_PERAPP]; + } + + ANS_LOGI("GetFlowCtrlConfigFromCCM success"); +} } // namespace Notification } // namespace OHOS diff --git a/services/ans/test/unittest/BUILD.gn b/services/ans/test/unittest/BUILD.gn index 86637a419d37288eb7b163d38b64d6bf600dfc3b..8c05f06e180bbd420dd838b3daf5c0b54f7f265f 100644 --- a/services/ans/test/unittest/BUILD.gn +++ b/services/ans/test/unittest/BUILD.gn @@ -487,6 +487,7 @@ ohos_unittest("notification_publish_service_test") { sources = [ "${test_path}/mock/mock_tokenid_kit.cpp", + "advanced_notification_flow_control_service_test.cpp", "advanced_notification_publish_service_test.cpp", "mock/blob.cpp", "mock/distributed_kv_data_manager.cpp", diff --git a/services/ans/test/unittest/advanced_notification_flow_control_service_test.cpp b/services/ans/test/unittest/advanced_notification_flow_control_service_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8e39292d9f64a5a87aef36787f3b1f706ac4865 --- /dev/null +++ b/services/ans/test/unittest/advanced_notification_flow_control_service_test.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "advanced_notification_flow_control_service.h" + +#include "gtest/gtest.h" + +#include "ans_const_define.h" +#include "ans_inner_errors.h" + +using namespace testing::ext; + +namespace OHOS { +namespace Notification { +namespace { + constexpr int32_t NON_SYSTEM_APP_UID = 1000; +} +class FlowControlServiceTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void FlowControlServiceTest::SetUpTestCase() {} + +void FlowControlServiceTest::TearDownTestCase() {} + +void FlowControlServiceTest::SetUp() {} + +void FlowControlServiceTest::TearDown() {} + +/** + * @tc.number : FlowControl_00001 + * @tc.name : Test FlowControl + * @tc.desc : Test FlowControl + */ +HWTEST_F(FlowControlServiceTest, FlowControl_00001, Function | SmallTest | Level1) +{ + sptr request = new (std::nothrow) NotificationRequest(); + sptr notification = new (std::nothrow) Notification(request); + auto record = std::make_shared(); + record->request = request; + record->notification = notification; + record->isThirdparty = false; + record->isNeedFlowCtrl = true; + ErrCode result = ERR_OK; + int32_t callingUid = DEFAULT_UID; + + // create flow control + // single app flow control test + for (int i = 0; i < MAX_CREATE_NUM_PERSECOND_PERAPP; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); + + // global flow control test + int gap = MAX_CREATE_NUM_PERSECOND - MAX_CREATE_NUM_PERSECOND_PERAPP; + callingUid = NON_SYSTEM_APP_UID; + for (int i = 0; i < gap; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); + + // update flow control + // single app flow control test + callingUid = DEFAULT_UID; + for (int i = 0; i < MAX_UPDATE_NUM_PERSECOND_PERAPP; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); + + // global flow control test + gap = MAX_UPDATE_NUM_PERSECOND - MAX_UPDATE_NUM_PERSECOND_PERAPP; + callingUid = NON_SYSTEM_APP_UID; + for (int i = 0; i < gap; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/services/ans/test/unittest/advanced_notification_service_test.cpp b/services/ans/test/unittest/advanced_notification_service_test.cpp index 1aae93d2efbd100125217cddb3549f5b7f34a895..2c22c94b90c3c28d8495db0a81601555d07d50f0 100644 --- a/services/ans/test/unittest/advanced_notification_service_test.cpp +++ b/services/ans/test/unittest/advanced_notification_service_test.cpp @@ -3821,375 +3821,5 @@ HWTEST_F(AdvancedNotificationServiceTest, PublishInNotificationList_00001, Funct advancedNotificationService_->PublishInNotificationList(record); ASSERT_EQ(advancedNotificationService_->notificationList_.size(), 100); } - -/** - * @tc.number : PublishGlobalFlowCtrl_00001 - * @tc.name : Test PublishGlobalFlowCtrl - * @tc.desc : Test PublishGlobalFlowCtrl - */ -HWTEST_F(AdvancedNotificationServiceTest, PublishGlobalFlowCtrl_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->flowControlPublishTimestampList_.clear(); - advancedNotificationService_->systemFlowControlPublishTimestampList_.clear(); - sptr request = new (std::nothrow) NotificationRequest(); - sptr notification = new (std::nothrow) Notification(request); - auto record = std::make_shared(); - record->request = request; - record->notification = notification; - record->isThirdparty = false; - record->isNeedFlowCtrl = true; - ErrCode result = ERR_OK; - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - for (int i = 0; i < advancedNotificationService_->maxCreateNumPerSecond; i++) { - result = advancedNotificationService_->PublishGlobalFlowCtrl(record, now); - advancedNotificationService_->systemFlowControlPublishTimestampList_.push_back(now); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->PublishGlobalFlowCtrl(record, now); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - - record->isThirdparty = true; - for (int i = 0; i < advancedNotificationService_->maxCreateNumPerSecond; i++) { - result = advancedNotificationService_->PublishGlobalFlowCtrl(record, now); - advancedNotificationService_->flowControlPublishTimestampList_.push_back(now); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->PublishGlobalFlowCtrl(record, now); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - - advancedNotificationService_->flowControlPublishTimestampList_.clear(); - advancedNotificationService_->systemFlowControlPublishTimestampList_.clear(); -} - -/** - * @tc.number : PublishSingleAppFlowCtrl_00001 - * @tc.name : Test PublishSingleAppFlowCtrl - * @tc.desc : Test PublishSingleAppFlowCtrl - */ -HWTEST_F(AdvancedNotificationServiceTest, PublishSingleAppFlowCtrl_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); - sptr request = new (std::nothrow) NotificationRequest(); - sptr notification = new (std::nothrow) Notification(request); - auto record = std::make_shared(); - record->request = request; - record->notification = notification; - record->isNeedFlowCtrl = true; - ErrCode result = ERR_OK; - const int32_t callingUid = DEFAULT_UID; - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_[callingUid] = - std::make_shared>(); - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - for (int i = 0; i < advancedNotificationService_->maxCreateNumPerSecondPerApp; i++) { - result = advancedNotificationService_->PublishSingleAppFlowCtrl(record, now, callingUid); - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_[callingUid]->push_back(now); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->PublishSingleAppFlowCtrl(record, now, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); -} - -/** - * @tc.number : PublishSingleAppFlowCtrlRemoveExpire_00001 - * @tc.name : Test PublishSingleAppFlowCtrlRemoveExpire - * @tc.desc : Test PublishSingleAppFlowCtrlRemoveExpire - */ -HWTEST_F(AdvancedNotificationServiceTest, PublishSingleAppFlowCtrlRemoveExpire_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); - - int32_t callingUid = DEFAULT_UID; - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_[callingUid] = - std::make_shared>(); - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_[callingUid]->push_back(now); - callingUid = NON_SYSTEM_APP_UID; - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_[callingUid] = - std::make_shared>(); - now = now + SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME; - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_[callingUid]->push_back(now); - now = now + SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME; - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.size(), 2); - advancedNotificationService_->PublishSingleAppFlowCtrlRemoveExpire(now); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.size(), 1); - now = now + SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME; - advancedNotificationService_->PublishSingleAppFlowCtrlRemoveExpire(now); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.size(), 0); - - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); -} - -/** - * @tc.number : PublishFlowCtrl_00001 - * @tc.name : Test PublishFlowCtrl - * @tc.desc : Test PublishFlowCtrl - */ -HWTEST_F(AdvancedNotificationServiceTest, PublishFlowCtrl_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->flowControlPublishTimestampList_.clear(); - advancedNotificationService_->systemFlowControlPublishTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); - sptr request = new (std::nothrow) NotificationRequest(); - sptr notification = new (std::nothrow) Notification(request); - auto record = std::make_shared(); - record->request = request; - record->notification = notification; - record->isThirdparty = false; - record->isNeedFlowCtrl = true; - ErrCode result = ERR_OK; - int32_t callingUid = DEFAULT_UID; - - // single app flow control test - for (int i = 0; i < advancedNotificationService_->maxCreateNumPerSecondPerApp; i++) { - result = advancedNotificationService_->PublishFlowCtrl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->PublishFlowCtrl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.size(), 1); - - // global flow control test - int gap = advancedNotificationService_->maxCreateNumPerSecond - - advancedNotificationService_->maxCreateNumPerSecondPerApp; - callingUid = NON_SYSTEM_APP_UID; - for (int i = 0; i < gap; i++) { - result = advancedNotificationService_->PublishFlowCtrl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->PublishFlowCtrl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.size(), 2); - - advancedNotificationService_->flowControlPublishTimestampList_.clear(); - advancedNotificationService_->systemFlowControlPublishTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); -} - -/** - * @tc.number : UpdateGlobalFlowCtrl_00001 - * @tc.name : Test UpdateGlobalFlowCtrl - * @tc.desc : Test UpdateGlobalFlowCtrl - */ -HWTEST_F(AdvancedNotificationServiceTest, UpdateGlobalFlowCtrl_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->flowControlUpdateTimestampList_.clear(); - advancedNotificationService_->systemFlowControlUpdateTimestampList_.clear(); - sptr request = new (std::nothrow) NotificationRequest(); - sptr notification = new (std::nothrow) Notification(request); - auto record = std::make_shared(); - record->request = request; - record->notification = notification; - record->isThirdparty = false; - record->isNeedFlowCtrl = true; - ErrCode result = ERR_OK; - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - for (int i = 0; i < advancedNotificationService_->maxUpdateNumPerSecond; i++) { - result = advancedNotificationService_->UpdateGlobalFlowCtrl(record, now); - advancedNotificationService_->systemFlowControlUpdateTimestampList_.push_back(now); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->UpdateGlobalFlowCtrl(record, now); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); - - record->isThirdparty = true; - for (int i = 0; i < advancedNotificationService_->maxUpdateNumPerSecond; i++) { - result = advancedNotificationService_->UpdateGlobalFlowCtrl(record, now); - advancedNotificationService_->flowControlUpdateTimestampList_.push_back(now); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->UpdateGlobalFlowCtrl(record, now); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); - - advancedNotificationService_->flowControlUpdateTimestampList_.clear(); - advancedNotificationService_->systemFlowControlUpdateTimestampList_.clear(); -} - -/** - * @tc.number : UpdateSingleAppFlowCtrl_00001 - * @tc.name : Test UpdateSingleAppFlowCtrl - * @tc.desc : Test UpdateSingleAppFlowCtrl - */ -HWTEST_F(AdvancedNotificationServiceTest, UpdateSingleAppFlowCtrl_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); - sptr request = new (std::nothrow) NotificationRequest(); - sptr notification = new (std::nothrow) Notification(request); - auto record = std::make_shared(); - record->request = request; - record->notification = notification; - record->isNeedFlowCtrl = true; - ErrCode result = ERR_OK; - const int32_t callingUid = DEFAULT_UID; - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_[callingUid] = - std::make_shared>(); - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - for (int i = 0; i < advancedNotificationService_->maxUpdateNumPerSecondPerApp; i++) { - result = advancedNotificationService_->UpdateSingleAppFlowCtrl(record, now, callingUid); - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_[callingUid]->push_back(now); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->UpdateSingleAppFlowCtrl(record, now, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); - - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); -} - -/** - * @tc.number : UpdateSingleAppFlowCtrlRemoveExpire_00001 - * @tc.name : Test UpdateSingleAppFlowCtrlRemoveExpire - * @tc.desc : Test UpdateSingleAppFlowCtrlRemoveExpire - */ -HWTEST_F(AdvancedNotificationServiceTest, UpdateSingleAppFlowCtrlRemoveExpire_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); - - int32_t callingUid = DEFAULT_UID; - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_[callingUid] = - std::make_shared>(); - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_[callingUid]->push_back(now); - callingUid = NON_SYSTEM_APP_UID; - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_[callingUid] = - std::make_shared>(); - now = now + SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME; - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_[callingUid]->push_back(now); - now = now + SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME; - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.size(), 2); - advancedNotificationService_->UpdateSingleAppFlowCtrlRemoveExpire(now); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.size(), 1); - now = now + SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME; - advancedNotificationService_->UpdateSingleAppFlowCtrlRemoveExpire(now); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.size(), 0); - - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); -} - -/** - * @tc.number : UpdateFlowCtrl_00001 - * @tc.name : Test UpdateFlowCtrl - * @tc.desc : Test UpdateFlowCtrl - */ -HWTEST_F(AdvancedNotificationServiceTest, UpdateFlowCtrl_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->flowControlUpdateTimestampList_.clear(); - advancedNotificationService_->systemFlowControlUpdateTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); - sptr request = new (std::nothrow) NotificationRequest(); - sptr notification = new (std::nothrow) Notification(request); - auto record = std::make_shared(); - record->request = request; - record->notification = notification; - record->isThirdparty = false; - record->isNeedFlowCtrl = true; - ErrCode result = ERR_OK; - int32_t callingUid = DEFAULT_UID; - - // single app flow control test - for (int i = 0; i < advancedNotificationService_->maxUpdateNumPerSecondPerApp; i++) { - result = advancedNotificationService_->UpdateFlowCtrl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->UpdateFlowCtrl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.size(), 1); - - // global flow control test - int gap = advancedNotificationService_->maxUpdateNumPerSecond - - advancedNotificationService_->maxUpdateNumPerSecondPerApp; - callingUid = NON_SYSTEM_APP_UID; - for (int i = 0; i < gap; i++) { - result = advancedNotificationService_->UpdateFlowCtrl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->UpdateFlowCtrl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.size(), 2); - - advancedNotificationService_->flowControlUpdateTimestampList_.clear(); - advancedNotificationService_->systemFlowControlUpdateTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); -} - -/** - * @tc.number : FlowControl_00001 - * @tc.name : Test FlowControl - * @tc.desc : Test FlowControl - */ -HWTEST_F(AdvancedNotificationServiceTest, FlowControl_00001, Function | SmallTest | Level1) -{ - advancedNotificationService_->flowControlPublishTimestampList_.clear(); - advancedNotificationService_->systemFlowControlPublishTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); - advancedNotificationService_->flowControlUpdateTimestampList_.clear(); - advancedNotificationService_->systemFlowControlUpdateTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); - advancedNotificationService_->notificationList_.clear(); - - sptr request = new (std::nothrow) NotificationRequest(); - sptr notification = new (std::nothrow) Notification(request); - auto record = std::make_shared(); - record->request = request; - record->notification = notification; - record->isThirdparty = false; - record->isNeedFlowCtrl = true; - ErrCode result = ERR_OK; - int32_t callingUid = DEFAULT_UID; - - // create flow control - // single app flow control test - for (int i = 0; i < advancedNotificationService_->maxCreateNumPerSecondPerApp; i++) { - result = advancedNotificationService_->FlowControl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->FlowControl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.size(), 1); - - // global flow control test - int gap = advancedNotificationService_->maxCreateNumPerSecond - - advancedNotificationService_->maxCreateNumPerSecondPerApp; - callingUid = NON_SYSTEM_APP_UID; - for (int i = 0; i < gap; i++) { - result = advancedNotificationService_->FlowControl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->FlowControl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.size(), 2); - - advancedNotificationService_->notificationList_.push_back(record); - // update flow control - // single app flow control test - callingUid = DEFAULT_UID; - for (int i = 0; i < advancedNotificationService_->maxUpdateNumPerSecondPerApp; i++) { - result = advancedNotificationService_->FlowControl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->FlowControl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.size(), 1); - - // global flow control test - gap = advancedNotificationService_->maxUpdateNumPerSecond - - advancedNotificationService_->maxUpdateNumPerSecondPerApp; - callingUid = NON_SYSTEM_APP_UID; - for (int i = 0; i < gap; i++) { - result = advancedNotificationService_->FlowControl(record, callingUid); - } - ASSERT_EQ(result, (int)ERR_OK); - result = advancedNotificationService_->FlowControl(record, callingUid); - ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); - ASSERT_EQ(advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.size(), 2); - - advancedNotificationService_->flowControlPublishTimestampList_.clear(); - advancedNotificationService_->systemFlowControlPublishTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlPublishTimestampMap_.clear(); - advancedNotificationService_->flowControlUpdateTimestampList_.clear(); - advancedNotificationService_->systemFlowControlUpdateTimestampList_.clear(); - advancedNotificationService_->singleAppFlowControlUpdateTimestampMap_.clear(); - advancedNotificationService_->notificationList_.clear(); -} } // namespace Notification } // namespace OHOS