diff --git a/src/app/clusters/basic/basic.cpp b/src/app/clusters/basic/basic.cpp index 130a1442c0e853..c0844f7c325c60 100644 --- a/src/app/clusters/basic/basic.cpp +++ b/src/app/clusters/basic/basic.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -329,10 +330,10 @@ CHIP_ERROR BasicAttrAccess::WriteLocation(AttributeValueDecoder & aDecoder) class PlatformMgrDelegate : public DeviceLayer::PlatformManagerDelegate { - // Gets called by the current Node after completing a boot or reboot process void OnStartUp(uint32_t softwareVersion) override { - ChipLogProgress(Zcl, "PlatformMgrDelegate: OnStartUp"); + // The StartUp event SHALL be emitted by a Node after completing a boot or reboot process + ChipLogDetail(Zcl, "Emitting StartUp event"); for (auto endpoint : EnabledEndpointsWithServerCluster(Basic::Id)) { @@ -343,15 +344,15 @@ class PlatformMgrDelegate : public DeviceLayer::PlatformManagerDelegate CHIP_ERROR err = LogEvent(event, endpoint, eventNumber); if (CHIP_NO_ERROR != err) { - ChipLogError(Zcl, "PlatformMgrDelegate: Failed to record StartUp event: %" CHIP_ERROR_FORMAT, err.Format()); + ChipLogError(Zcl, "Failed to emit StartUp event: %" CHIP_ERROR_FORMAT, err.Format()); } } } - // Gets called by the current Node prior to any orderly shutdown sequence on a best-effort basis. void OnShutDown() override { - ChipLogProgress(Zcl, "PlatformMgrDelegate: OnShutDown"); + // The ShutDown event SHOULD be emitted on a best-effort basis by a Node prior to any orderly shutdown sequence. + ChipLogDetail(Zcl, "Emitting ShutDown event"); for (auto endpoint : EnabledEndpointsWithServerCluster(Basic::Id)) { @@ -362,9 +363,12 @@ class PlatformMgrDelegate : public DeviceLayer::PlatformManagerDelegate CHIP_ERROR err = LogEvent(event, endpoint, eventNumber); if (CHIP_NO_ERROR != err) { - ChipLogError(Zcl, "PlatformMgrDelegate: Failed to record ShutDown event: %" CHIP_ERROR_FORMAT, err.Format()); + ChipLogError(Zcl, "Failed to emit ShutDown event: %" CHIP_ERROR_FORMAT, err.Format()); } } + + // Flush the events to increase chances that they get sent before the shutdown + InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleUrgentEventDeliverySync(); } }; diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 50b5b3f4e15862..137eb2cf974de2 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -45,6 +45,8 @@ #include #include +using namespace chip::DeviceLayer; + using chip::kMinValidFabricIndex; using chip::RendezvousInformationFlag; using chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr; @@ -75,16 +77,6 @@ void StopEventLoop(intptr_t arg) } } -void DispatchShutDownEvent(intptr_t arg) -{ - // The ShutDown event SHOULD be emitted on a best-effort basis by a Node prior to any orderly shutdown sequence. - chip::DeviceLayer::PlatformManagerDelegate * platformManagerDelegate = chip::DeviceLayer::PlatformMgr().GetDelegate(); - if (platformManagerDelegate != nullptr) - { - platformManagerDelegate->OnShutDown(); - } -} - } // namespace namespace chip { @@ -270,6 +262,8 @@ CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint RejoinExistingMulticastGroups(); #endif // !CHIP_DEVICE_CONFIG_ENABLE_THREAD + PlatformMgr().HandleServerStarted(); + exit: if (err != CHIP_NO_ERROR) { @@ -317,27 +311,18 @@ void Server::RejoinExistingMulticastGroups() void Server::DispatchShutDownAndStopEventLoop() { - chip::DeviceLayer::PlatformMgr().ScheduleWork(DispatchShutDownEvent); - chip::DeviceLayer::PlatformMgr().ScheduleWork(StopEventLoop); + PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().HandleServerShuttingDown(); }); + PlatformMgr().ScheduleWork(StopEventLoop); } void Server::ScheduleFactoryReset() { - chip::DeviceLayer::PlatformMgr().ScheduleWork(FactoryReset); -} - -void Server::FactoryReset(intptr_t arg) -{ - // Delete all fabrics and emit Leave event. - GetInstance().GetFabricTable().DeleteAllFabrics(); - - // Emit Shutdown event, as shutdown will come after factory reset. - DispatchShutDownEvent(0); - - // Flush all dispatched events. - chip::app::InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleUrgentEventDeliverySync(); - - chip::DeviceLayer::ConfigurationMgr().InitiateFactoryReset(); + PlatformMgr().ScheduleWork([](intptr_t) { + // Delete all fabrics and emit Leave event. + GetInstance().GetFabricTable().DeleteAllFabrics(); + PlatformMgr().HandleServerShuttingDown(); + ConfigurationMgr().InitiateFactoryReset(); + }); } void Server::Shutdown() diff --git a/src/app/server/Server.h b/src/app/server/Server.h index a0aab30f1e7e3d..642e7ea398551a 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -104,8 +104,6 @@ class Server void ScheduleFactoryReset(); - static void FactoryReset(intptr_t arg); - static Server & GetInstance() { return sServer; } private: diff --git a/src/include/platform/PlatformManager.h b/src/include/platform/PlatformManager.h index eacd0cbfa450e6..bbf9ce3ea8c000 100644 --- a/src/include/platform/PlatformManager.h +++ b/src/include/platform/PlatformManager.h @@ -117,6 +117,18 @@ class PlatformManager void SetDelegate(PlatformManagerDelegate * delegate) { mDelegate = delegate; } PlatformManagerDelegate * GetDelegate() const { return mDelegate; } + /** + * Should be called after initializing all layers of the Matter stack to + * run all needed post-startup actions. + */ + void HandleServerStarted(); + + /** + * Should be called before shutting down the Matter stack or restarting the + * application to run all needed pre-shutdown actions. + */ + void HandleServerShuttingDown(); + /** * ScheduleWork can be called after InitChipStack has been called. Calls * that happen before either StartEventLoopTask or RunEventLoop will queue @@ -342,6 +354,16 @@ inline void PlatformManager::RemoveEventHandler(EventHandlerFunct handler, intpt static_cast(this)->_RemoveEventHandler(handler, arg); } +inline void PlatformManager::HandleServerStarted() +{ + static_cast(this)->_HandleServerStarted(); +} + +inline void PlatformManager::HandleServerShuttingDown() +{ + static_cast(this)->_HandleServerShuttingDown(); +} + inline void PlatformManager::ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg) { static_cast(this)->_ScheduleWork(workFunct, arg); diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.cpp b/src/include/platform/internal/GenericPlatformManagerImpl.cpp index e9251982f99ffd..cc14a287abba2e 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl.cpp @@ -121,10 +121,6 @@ CHIP_ERROR GenericPlatformManagerImpl::_InitChipStack() SuccessOrExit(err); - // TODO Initialize the Software Update Manager object. - - _ScheduleWork(HandleDeviceRebooted, 0); - exit: return err; } @@ -195,6 +191,40 @@ void GenericPlatformManagerImpl::_RemoveEventHandler(PlatformManager: } } +template +void GenericPlatformManagerImpl::_HandleServerStarted() +{ + PlatformManagerDelegate * platformManagerDelegate = PlatformMgr().GetDelegate(); + GeneralDiagnosticsDelegate * generalDiagnosticsDelegate = GetDiagnosticDataProvider().GetGeneralDiagnosticsDelegate(); + + if (platformManagerDelegate != nullptr) + { + uint32_t softwareVersion; + + if (ConfigurationMgr().GetSoftwareVersion(softwareVersion) == CHIP_NO_ERROR) + platformManagerDelegate->OnStartUp(softwareVersion); + } + + if (generalDiagnosticsDelegate != nullptr) + { + uint8_t bootReason; + + if (GetDiagnosticDataProvider().GetBootReason(bootReason) == CHIP_NO_ERROR) + generalDiagnosticsDelegate->OnDeviceRebooted(static_cast(bootReason)); + } +} + +template +void GenericPlatformManagerImpl::_HandleServerShuttingDown() +{ + PlatformManagerDelegate * platformManagerDelegate = PlatformMgr().GetDelegate(); + + if (platformManagerDelegate != nullptr) + { + platformManagerDelegate->OnShutDown(); + } +} + template void GenericPlatformManagerImpl::_ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg) { @@ -290,30 +320,6 @@ void GenericPlatformManagerImpl::HandleMessageLayerActivityChanged(bo } } -template -void GenericPlatformManagerImpl::HandleDeviceRebooted(intptr_t arg) -{ - PlatformManagerDelegate * platformManagerDelegate = PlatformMgr().GetDelegate(); - GeneralDiagnosticsDelegate * generalDiagnosticsDelegate = GetDiagnosticDataProvider().GetGeneralDiagnosticsDelegate(); - - if (generalDiagnosticsDelegate != nullptr) - { - uint8_t bootReason; - - if (GetDiagnosticDataProvider().GetBootReason(bootReason) == CHIP_NO_ERROR) - generalDiagnosticsDelegate->OnDeviceRebooted(static_cast(bootReason)); - } - - // The StartUp event SHALL be emitted by a Node after completing a boot or reboot process - if (platformManagerDelegate != nullptr) - { - uint32_t softwareVersion; - - if (ConfigurationMgr().GetSoftwareVersion(softwareVersion) == CHIP_NO_ERROR) - platformManagerDelegate->OnStartUp(softwareVersion); - } -} - // Fully instantiate the generic implementation class in whatever compilation unit includes this file. template class GenericPlatformManagerImpl; diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.h b/src/include/platform/internal/GenericPlatformManagerImpl.h index d38ae34b60c7f4..e2b1944b9682f7 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.h +++ b/src/include/platform/internal/GenericPlatformManagerImpl.h @@ -55,6 +55,8 @@ class GenericPlatformManagerImpl CHIP_ERROR _Shutdown(); CHIP_ERROR _AddEventHandler(PlatformManager::EventHandlerFunct handler, intptr_t arg); void _RemoveEventHandler(PlatformManager::EventHandlerFunct handler, intptr_t arg); + void _HandleServerStarted(); + void _HandleServerShuttingDown(); void _ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg); void _DispatchEvent(const ChipDeviceEvent * event); @@ -78,7 +80,6 @@ class GenericPlatformManagerImpl private: bool mMsgLayerWasActive; - static void HandleDeviceRebooted(intptr_t arg); ImplClass * Impl() { return static_cast(this); } }; diff --git a/src/platform/fake/PlatformManagerImpl.h b/src/platform/fake/PlatformManagerImpl.h index 7ac17c3ff36bf9..b15a23d8a82e5a 100644 --- a/src/platform/fake/PlatformManagerImpl.h +++ b/src/platform/fake/PlatformManagerImpl.h @@ -49,6 +49,8 @@ class PlatformManagerImpl final : public PlatformManager CHIP_ERROR _AddEventHandler(EventHandlerFunct handler, intptr_t arg = 0) { return CHIP_ERROR_NOT_IMPLEMENTED; } void _RemoveEventHandler(EventHandlerFunct handler, intptr_t arg = 0) {} + void _HandleServerStarted() {} + void _HandleServerShuttingDown() {} void _ScheduleWork(AsyncWorkFunct workFunct, intptr_t arg = 0) {} void _RunEventLoop() diff --git a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h index 047de04dfba017..8ddf607d5d8239 100644 --- a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h +++ b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h @@ -67,6 +67,12 @@ #define CHIP_DEVICE_CONFIG_OTA_REQUESTOR_REBOOT_DELAY_MS 1000 #endif // CHIP_DEVICE_CONFIG_OTA_REQUESTOR_REBOOT_DELAY_MS +#ifndef CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS +/// Time to sleep after running server shutdown actions to let lower layers complete the actions. +/// This may include transmitting packets created by the actions. +#define CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS 10 +#endif // CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS + // ========== Platform-specific Configuration Overrides ========= #ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp index f62c5578af3831..8dda149f3c44c4 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp @@ -61,9 +61,14 @@ CHIP_ERROR OTAImageProcessorImpl::Apply() ReturnErrorOnFailure(System::MapErrorZephyr(dfu_target_done(true))); #ifdef CONFIG_CHIP_OTA_REQUESTOR_REBOOT_ON_APPLY - return DeviceLayer::SystemLayer().StartTimer( + return SystemLayer().StartTimer( System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_OTA_REQUESTOR_REBOOT_DELAY_MS), - [](System::Layer *, void * /* context */) { sys_reboot(SYS_REBOOT_WARM); }, nullptr /* context */); + [](System::Layer *, void * /* context */) { + PlatformMgr().HandleServerShuttingDown(); + k_msleep(CHIP_DEVICE_CONFIG_SERVER_SHUTDOWN_ACTIONS_SLEEP_MS); + sys_reboot(SYS_REBOOT_WARM); + }, + nullptr /* context */); #else return CHIP_NO_ERROR; #endif