diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index fd286ff7c9c2d4..1ee02cd71d5fc2 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -150,6 +150,10 @@ source_set("test-event-trigger") { sources = [ "TestEventTriggerDelegate.h" ] } +source_set("event-reporter") { + sources = [ "EventReporter.h" ] +} + # interaction-model is a static-library because it currently requires global functions (app/util/...) that are stubbed in different test files that depend on the app static_library # which in tern depens on the interaction-model. # Using source_set prevents the unit test to build correctly. @@ -211,6 +215,7 @@ static_library("interaction-model") { ":app_config", ":command-handler-impl", ":constants", + ":event-reporter", ":paths", ":subscription-info-provider", "${chip_root}/src/app/MessageDef", @@ -456,6 +461,7 @@ static_library("app") { ":app_config", ":attribute-access", ":constants", + ":event-reporter", ":global-attributes", ":interaction-model", "${chip_root}/src/app/data-model", diff --git a/src/app/EventManagement.cpp b/src/app/EventManagement.cpp index 4c01bedf4b9a5b..1321475d3e8314 100644 --- a/src/app/EventManagement.cpp +++ b/src/app/EventManagement.cpp @@ -83,7 +83,7 @@ struct CopyAndAdjustDeltaTimeContext void EventManagement::Init(Messaging::ExchangeManager * apExchangeManager, uint32_t aNumBuffers, CircularEventBuffer * apCircularEventBuffer, const LogStorageResources * const apLogStorageResources, MonotonicallyIncreasingCounter * apEventNumberCounter, - System::Clock::Milliseconds64 aMonotonicStartupTime) + System::Clock::Milliseconds64 aMonotonicStartupTime, EventReporter * apEventReporter) { CircularEventBuffer * current = nullptr; CircularEventBuffer * prev = nullptr; @@ -124,6 +124,16 @@ void EventManagement::Init(Messaging::ExchangeManager * apExchangeManager, uint3 mBytesWritten = 0; mMonotonicStartupTime = aMonotonicStartupTime; + + // TODO(#36890): Should remove using the global instance and rely only on passed in variable. + if (apEventReporter == nullptr) + { + mpEventReporter = &InteractionModelEngine::GetInstance()->GetReportingEngine(); + } + else + { + mpEventReporter = apEventReporter; + } } CHIP_ERROR EventManagement::CopyToNextBuffer(CircularEventBuffer * apEventBuffer) @@ -490,7 +500,7 @@ CHIP_ERROR EventManagement::LogEventPrivate(EventLoggingDelegate * apDelegate, c opts.mTimestamp.mType == Timestamp::Type::kSystem ? "Sys" : "Epoch", ChipLogValueX64(opts.mTimestamp.mValue)); #endif // CHIP_CONFIG_EVENT_LOGGING_VERBOSE_DEBUG_LOGS - err = InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleEventDelivery(opts.mPath, mBytesWritten); + err = mpEventReporter->NewEventGenerated(opts.mPath, mBytesWritten); } return err; diff --git a/src/app/EventManagement.h b/src/app/EventManagement.h index 76220350fc2507..f5687b586e02f4 100644 --- a/src/app/EventManagement.h +++ b/src/app/EventManagement.h @@ -29,6 +29,7 @@ #include "EventLoggingDelegate.h" #include #include +#include #include #include #include @@ -225,11 +226,13 @@ class EventManagement : public DataModel::EventsGenerator * time 0" for cases when we use * system-time event timestamps. * + * @param[in] apEventReporter Event reporter to be notified when events are generated. + * */ void Init(Messaging::ExchangeManager * apExchangeManager, uint32_t aNumBuffers, CircularEventBuffer * apCircularEventBuffer, const LogStorageResources * const apLogStorageResources, MonotonicallyIncreasingCounter * apEventNumberCounter, - System::Clock::Milliseconds64 aMonotonicStartupTime); + System::Clock::Milliseconds64 aMonotonicStartupTime, EventReporter * apEventReporter = nullptr); static EventManagement & GetInstance(); @@ -563,6 +566,8 @@ class EventManagement : public DataModel::EventsGenerator Timestamp mLastEventTimestamp; ///< The timestamp of the last event in this buffer System::Clock::Milliseconds64 mMonotonicStartupTime; + + EventReporter * mpEventReporter = nullptr; }; } // namespace app diff --git a/src/app/EventReporter.h b/src/app/EventReporter.h new file mode 100644 index 00000000000000..7a87b580931cdc --- /dev/null +++ b/src/app/EventReporter.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace app { + +/** + * Interface that EventManagement can use to notify when events are generated and may need reporting. + * + */ +class EventReporter +{ +public: + virtual ~EventReporter() = default; + + /** + * Notify that an event was generated. + * + * @param[in] aPath The path that identifies the kind of event that was generated. + * @param[in] aBytesConsumed The number of bytes needed to store the event in EventManagement. + */ + CHIP_ERROR virtual NewEventGenerated(ConcreteEventPath & aPath, uint32_t aBytesConsumed) = 0; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 78967c6d53c680..2fafe375f07e12 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -149,7 +149,8 @@ InteractionModelEngine * InteractionModelEngine::GetInstance() CHIP_ERROR InteractionModelEngine::Init(Messaging::ExchangeManager * apExchangeMgr, FabricTable * apFabricTable, reporting::ReportScheduler * reportScheduler, CASESessionManager * apCASESessionMgr, - SubscriptionResumptionStorage * subscriptionResumptionStorage) + SubscriptionResumptionStorage * subscriptionResumptionStorage, + EventManagement * eventManagement) { VerifyOrReturnError(apFabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(apExchangeMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT); @@ -165,7 +166,7 @@ CHIP_ERROR InteractionModelEngine::Init(Messaging::ExchangeManager * apExchangeM ReturnErrorOnFailure(mpFabricTable->AddFabricDelegate(this)); ReturnErrorOnFailure(mpExchangeMgr->RegisterUnsolicitedMessageHandlerForProtocol(Protocols::InteractionModel::Id, this)); - mReportingEngine.Init(); + mReportingEngine.Init((eventManagement != nullptr) ? eventManagement : &EventManagement::GetInstance()); StatusIB::RegisterErrorFormatter(); diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index 36aa2ccc6e3dd9..c5a4a0811d274b 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -126,11 +126,13 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler, * @param[in] apExchangeMgr A pointer to the ExchangeManager object. * @param[in] apFabricTable A pointer to the FabricTable object. * @param[in] apCASESessionMgr An optional pointer to a CASESessionManager (used for re-subscriptions). + * @parma[in] eventManagement An optional pointer to a EventManagement. If null, the global instance will be used. * */ CHIP_ERROR Init(Messaging::ExchangeManager * apExchangeMgr, FabricTable * apFabricTable, reporting::ReportScheduler * reportScheduler, CASESessionManager * apCASESessionMgr = nullptr, - SubscriptionResumptionStorage * subscriptionResumptionStorage = nullptr); + SubscriptionResumptionStorage * subscriptionResumptionStorage = nullptr, + EventManagement * eventManagement = nullptr); void Shutdown(); diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp index e2691e519ac13d..a9cef5c27dc333 100644 --- a/src/app/reporting/Engine.cpp +++ b/src/app/reporting/Engine.cpp @@ -221,10 +221,13 @@ bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const Concrete Engine::Engine(InteractionModelEngine * apImEngine) : mpImEngine(apImEngine) {} -CHIP_ERROR Engine::Init() +CHIP_ERROR Engine::Init(EventManagement * apEventManagement) { + VerifyOrReturnError(apEventManagement != nullptr, CHIP_ERROR_INVALID_ARGUMENT); mNumReportsInFlight = 0; mCurReadHandlerIdx = 0; + mpEventManagement = apEventManagement; + return CHIP_NO_ERROR; } @@ -560,20 +563,20 @@ CHIP_ERROR Engine::BuildSingleReportDataEventReports(ReportDataMessage::Builder size_t eventCount = 0; bool hasEncodedStatus = false; TLV::TLVWriter backup; - bool eventClean = true; - auto & eventMin = apReadHandler->GetEventMin(); - EventManagement & eventManager = EventManagement::GetInstance(); - bool hasMoreChunks = false; + bool eventClean = true; + auto & eventMin = apReadHandler->GetEventMin(); + bool hasMoreChunks = false; aReportDataBuilder.Checkpoint(backup); VerifyOrExit(apReadHandler->GetEventPathList() != nullptr, ); - // If the eventManager is not valid or has not been initialized, + // If the mpEventManagement is not valid or has not been initialized, // skip the rest of processing - VerifyOrExit(eventManager.IsValid(), ChipLogError(DataManagement, "EventManagement has not yet initialized")); + VerifyOrExit(mpEventManagement != nullptr && mpEventManagement->IsValid(), + ChipLogError(DataManagement, "EventManagement has not yet initialized")); - eventClean = apReadHandler->CheckEventClean(eventManager); + eventClean = apReadHandler->CheckEventClean(*mpEventManagement); // proceed only if there are new events. if (eventClean) @@ -593,8 +596,8 @@ CHIP_ERROR Engine::BuildSingleReportDataEventReports(ReportDataMessage::Builder err = CheckAccessDeniedEventPaths(*(eventReportIBs.GetWriter()), hasEncodedStatus, apReadHandler); SuccessOrExit(err); - err = eventManager.FetchEventsSince(*(eventReportIBs.GetWriter()), apReadHandler->GetEventPathList(), eventMin, eventCount, - apReadHandler->GetSubjectDescriptor()); + err = mpEventManagement->FetchEventsSince(*(eventReportIBs.GetWriter()), apReadHandler->GetEventPathList(), eventMin, + eventCount, apReadHandler->GetSubjectDescriptor()); if ((err == CHIP_END_OF_TLV) || (err == CHIP_ERROR_TLV_UNDERRUN) || (err == CHIP_NO_ERROR)) { @@ -1128,7 +1131,7 @@ CHIP_ERROR Engine::ScheduleBufferPressureEventDelivery(uint32_t aBytesWritten) return CHIP_NO_ERROR; } -CHIP_ERROR Engine::ScheduleEventDelivery(ConcreteEventPath & aPath, uint32_t aBytesWritten) +CHIP_ERROR Engine::NewEventGenerated(ConcreteEventPath & aPath, uint32_t aBytesConsumed) { // If we literally have no read handlers right now that care about any events, // we don't need to call schedule run for event. @@ -1166,7 +1169,7 @@ CHIP_ERROR Engine::ScheduleEventDelivery(ConcreteEventPath & aPath, uint32_t aBy return CHIP_NO_ERROR; } - return ScheduleBufferPressureEventDelivery(aBytesWritten); + return ScheduleBufferPressureEventDelivery(aBytesConsumed); } void Engine::ScheduleUrgentEventDeliverySync(Optional fabricIndex) diff --git a/src/app/reporting/Engine.h b/src/app/reporting/Engine.h index a16b0d9151d3d9..6f60da7d8f9caf 100644 --- a/src/app/reporting/Engine.h +++ b/src/app/reporting/Engine.h @@ -25,6 +25,7 @@ #pragma once #include +#include #include #include #include @@ -55,7 +56,7 @@ namespace reporting { * At its core, it tries to gather and pack as much relevant attributes changes and/or events as possible into a report * message before sending that to the reader. It continues to do so until it has no more work to do. */ -class Engine : public DataModel::ProviderChangeListener +class Engine : public DataModel::ProviderChangeListener, public EventReporter { public: /** @@ -66,10 +67,12 @@ class Engine : public DataModel::ProviderChangeListener /** * Initializes the reporting engine. Should only be called once. * + * @param[in] A pointer to EventManagement, should not be a nullptr. + * * @retval #CHIP_NO_ERROR On success. * @retval other Was unable to retrieve data and write it into the writer. */ - CHIP_ERROR Init(); + CHIP_ERROR Init(EventManagement * apEventManagement); void Shutdown(); @@ -96,13 +99,6 @@ class Engine : public DataModel::ProviderChangeListener */ CHIP_ERROR SetDirty(const AttributePathParams & aAttributePathParams); - /** - * @brief - * Schedule the event delivery - * - */ - CHIP_ERROR ScheduleEventDelivery(ConcreteEventPath & aPath, uint32_t aBytesWritten); - /* * Resets the tracker that tracks the currently serviced read handler. * apReadHandler can be non-null to indicate that the reset is due to a @@ -182,6 +178,12 @@ class Engine : public DataModel::ProviderChangeListener bool IsClusterDataVersionMatch(const SingleLinkedListNode * aDataVersionFilterList, const ConcreteReadAttributePath & aPath); + /** + * EventReporter implementation. + * + */ + CHIP_ERROR NewEventGenerated(ConcreteEventPath & aPath, uint32_t aBytesConsumed) override; + /** * Send Report via ReadHandler * @@ -287,6 +289,8 @@ class Engine : public DataModel::ProviderChangeListener #endif InteractionModelEngine * mpImEngine = nullptr; + + EventManagement * mpEventManagement = nullptr; }; }; // namespace reporting