Skip to content

[Server::Shutdown] Fix the matter server shutdown sequence, introduced few APIs to do *ClusterServerShutdown so that we can reinitialise the matter server without reboot on embedded platforms. #38515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
60 changes: 33 additions & 27 deletions src/app/InteractionModelEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,39 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
#endif // CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
#endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS

/** Previously, ShutdowActiveReads() was only available in unit test builds via `#if CONFIG_BUILD_FOR_HOST_UNIT_TEST`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is ShutdowActiveReads?

* However, we now require proper cleanup of active read handlers during the application's shutdown sequence,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we are making this API public. We already shut down the read handlers in InteractionModelEngine::Shutdown. Why do we need a separate way of doing it? That sounds like something is just broken in our shutdown/startup sequencing.

As far as ReadClients: actual reads get shut down by shutting down sessions/exchanges, and subscriptions are shut down in InteractionModelEngine::Shutdown already, no? So again, this feels like a problem in our sequencing. But even if not, ShutdownAllSubscriptions is public API on IM engine.

* especially before calling SetDataModelProvider(nullptr). This ensures that there are no ongoing IM reads,
* which could otherwise result in crashes or undefined behavior.

* Therefore, this method has been moved out of the CONFIG_BUILD_FOR_HOST_UNIT_TEST block so that it can be
* called as part of the normal shutdown flow.

* Note: This was originally introduced for unit tests to clean up subscriptions created via the high-level
* APIs in src/controller/ReadInteraction.h, which did not expose a way to shut down active subscriptions.
**/

void ShutdownActiveReads()
{
#if CHIP_CONFIG_ENABLE_READ_CLIENT
for (auto * readClient = mpActiveReadClientList; readClient != nullptr;)
{
readClient->mpImEngine = nullptr;
auto * tmpClient = readClient->GetNextClient();
readClient->SetNextClient(nullptr);
readClient->Close(CHIP_NO_ERROR);
readClient = tmpClient;
}

//
// After that, we just null out our tracker.
//
mpActiveReadClientList = nullptr;
#endif // CHIP_CONFIG_ENABLE_READ_CLIENT

mReadHandlers.ReleaseAll();
}

#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
//
// Get direct access to the underlying read handler pool
Expand Down Expand Up @@ -391,33 +424,6 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
mSubscriptionResumptionRetrySecondsOverride = seconds;
}
#endif

//
// When testing subscriptions using the high-level APIs in src/controller/ReadInteraction.h,
// they don't provide for the ability to shut down those subscriptions after they've been established.
//
// So for the purposes of unit tests, add a helper here to shut down and clean-up all active handlers.
//
void ShutdownActiveReads()
{
#if CHIP_CONFIG_ENABLE_READ_CLIENT
for (auto * readClient = mpActiveReadClientList; readClient != nullptr;)
{
readClient->mpImEngine = nullptr;
auto * tmpClient = readClient->GetNextClient();
readClient->SetNextClient(nullptr);
readClient->Close(CHIP_NO_ERROR);
readClient = tmpClient;
}

//
// After that, we just null out our tracker.
//
mpActiveReadClientList = nullptr;
#endif // CHIP_CONFIG_ENABLE_READ_CLIENT

mReadHandlers.ReleaseAll();
}
#endif

DataModel::Provider * GetDataModelProvider() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1302,3 +1302,10 @@ void CameraAvSettingsUserLevelMgmtServer::HandleDPTZRelativeMove(HandlerContext
*
*/
void MatterCameraAvSettingsUserLevelManagementPluginServerInitCallback() {}

/** @brief Camera AV Settings User Level Management Cluster Server Shutdown
*
* Server Shutdown
*
*/
void MatterCameraAvSettingsUserLevelManagementPluginServerShutdownCallback() {}
15 changes: 9 additions & 6 deletions src/app/clusters/scenes-server/scenes-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1153,12 +1153,15 @@ void emberAfScenesManagementClusterServerInitCallback(EndpointId endpoint)

void MatterScenesManagementClusterServerShutdownCallback(EndpointId endpoint)
{
uint16_t endpointTableSize = 0;
VerifyOrReturn(Status::Success == Attributes::SceneTableSize::Get(endpoint, &endpointTableSize));

// Get Scene Table Instance
SceneTable * sceneTable = scenes::GetSceneTableImpl(endpoint, endpointTableSize);
sceneTable->RemoveEndpoint();
// TODO: Remove the commented code.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this code leads to incorrect behavior on shutdown, but not having this code leads to incorrect behavior on endpoint removal (storage leaks). So just commenting it out is breaking critical things, and chances are we need to fix that before we can land this PR.

Have you talked to the authors of this code about this situation, like we discussed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I have talked with the owner @lpbeliveau-silabs. He dropped the comment #38515 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but who is doing that "moved to a different handler" bit and when? Because we can't ship things in the state that we will have after this PR....

Copy link
Contributor

@lpbeliveau-silabs lpbeliveau-silabs Jun 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to catch up with the changes and address this shortly. So to confirm, this specific behavior is for embedded systems that shutdown endpoints during power cycling, but don't necessarily remove them? Just want to make sure I got this right before implementing it. Will open a PR when I figure out what this "different handler" might be.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into the SDK, it seems like the previous intended behavior of Shutdown WAS to handle endpoints being removed. This PR is modifying this behavior and I do not think that this is a "Scenes is holding back the PR" situation. The distinction between Endpoint Shutdown vs Removal should either be added to the handler or we need to have some code responsible for cleanup on endpoint removal implemented along this change.

// MatterScenesManagementClusterServerShutdownCallback was not being called before and in the sceneTable->RemoveEndpoint();
// it removes the SceneTableEntry from the persistent storage.
// uint16_t endpointTableSize = 0;
// VerifyOrReturn(Status::Success == Attributes::SceneTableSize::Get(endpoint, &endpointTableSize));

// // Get Scene Table Instance
// SceneTable * sceneTable = scenes::GetSceneTableImpl(endpoint, endpointTableSize);
// sceneTable->RemoveEndpoint();
Comment on lines +1156 to +1164
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The existing shutdown logic for the Scenes cluster has been commented out, with a TODO indicating it needs to be removed. However, this logic (sceneTable->RemoveEndpoint()) seems crucial for cleaning up the SceneTableEntry from persistent storage during shutdown. Leaving this commented out means the Scenes cluster might not be cleaning up its resources correctly, which could lead to issues on subsequent server startups or resource leaks. Could you clarify if this cleanup is being handled elsewhere in the new shutdown flow, or if the commented-out code needs to be re-implemented or replaced?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TLDR: why are we checking in commented out code?

}

void MatterScenesManagementPluginServerInitCallback()
Expand Down
7 changes: 6 additions & 1 deletion src/app/clusters/scenes-server/scenes-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,12 @@ class ScenesServer : public CommandHandlerInterface, public AttributeAccessInter

private:
ScenesServer() : CommandHandlerInterface(Optional<EndpointId>(), Id), AttributeAccessInterface(Optional<EndpointId>(), Id) {}
~ScenesServer() { Shutdown(); }
~ScenesServer()
{
// TODO: Remove the commented code.
// ScenesServer::Shutdown is being called from MatterScenesManagementPluginServerShutdownCallback.
// Shutdown();
Comment on lines +111 to +113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the .cpp file, the call to Shutdown() in the ScenesServer destructor has been commented out with a TODO. If ScenesServer::Shutdown() contains necessary cleanup logic beyond what's handled by the new MatterScenesManagementPluginServerShutdownCallback, removing this call could lead to resource leaks or incorrect state on shutdown. Is the logic previously in ScenesServer::Shutdown() now handled by the new callback or elsewhere?

}

bool mIsInitialized = false;

Expand Down
11 changes: 11 additions & 0 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,14 @@ void Server::Shutdown()
#if CHIP_CONFIG_ENABLE_ICD_SERVER
app::DnssdServer::Instance().SetICDManager(nullptr);
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER

/** Shutdown all active read handlers to ensure a clean shutdown of the Interaction Model.
* This is required before resetting the DataModelProvider, as ongoing reads may access it
* and lead to crashes or undefined behavior.
**/
app::InteractionModelEngine::GetInstance()->ShutdownActiveReads();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again: during startup we first set the DM provider (line 320 in this diff), then do InteractionModelEngine::Init (line 393), right?

So during shutdown we should be doing InteractionModelEngine::Shutdown before clearing the DM provider, I would think. That's what #38515 was about. But for some reason, instead of moving SetDataModelProvider(nullptr) to the right place in the shutdown sequence we ended up adding this extra shutdown step....

It's not just reads that touch the DM provider, anyway (commands and writes do too), so you really have to InteractionModelEngine::Shutdown before clearing the provider.

If we did that, InteractionModelEngine::Shutdown would clear any active read handlers, as it already does. And clear subscription clients. Which would leave read clients.... Those would get shut down when we expire their sessions, but if we want to more proactively expire them, we could do that in the IM engine shutdown. Either way, read clients don't touch DM provider, right?


app::InteractionModelEngine::GetInstance()->SetDataModelProvider(nullptr);
app::DnssdServer::Instance().SetCommissioningModeProvider(nullptr);
Dnssd::ServiceAdvertiser::Instance().Shutdown();

Expand Down Expand Up @@ -681,11 +689,13 @@ void Server::Shutdown()
mCommissioningWindowManager.Shutdown();
mMessageCounterManager.Shutdown();
mExchangeMgr.Shutdown();
mFabrics.RemoveFabricDelegate(&mFabricDelegate);
mSessions.Shutdown();
mTransports.Close();
mAccessControl.Finish();
Access::ResetAccessControlToDefault();
Credentials::SetGroupDataProvider(nullptr);
app::EventManagement::GetInstance().DestroyEventManagement();
#if CHIP_CONFIG_ENABLE_ICD_SERVER
// Remove Test Event Trigger Handler
if (mTestEventTriggerDelegate != nullptr)
Expand All @@ -695,6 +705,7 @@ void Server::Shutdown()
mICDManager.Shutdown();
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER

mFabrics.Shutdown();
// TODO(16969): Remove chip::Platform::MemoryInit() call from Server class, it belongs to outer code
chip::Platform::MemoryShutdown();
}
Expand Down
3 changes: 2 additions & 1 deletion src/app/tests/test-ember-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ uint16_t emberAfGetClusterServerEndpointIndex(chip::EndpointId endpoint, chip::C
return endpoint;
}

// Mock function for linking
// Mock functions for linking
void InitDataModelHandler() {}
void ShutdownDataModelHandler() {}
5 changes: 5 additions & 0 deletions src/app/util/DataModelHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ void InitDataModelHandler()
emberAfEndpointConfigure();
emberAfInit();
}

void ShutdownDataModelHandler()
{
emberAfShutdown();
}
5 changes: 5 additions & 0 deletions src/app/util/DataModelHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@
* data model messages.
*/
void InitDataModelHandler();

/**
* Shutdown the data model.
*/
void ShutdownDataModelHandler();
2 changes: 2 additions & 0 deletions src/app/util/attribute-storage-detail.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ extern uint8_t attributeData[]; // main storage bucket for all attributes

void emAfCallInits();

void emAfCallShutdowns();

chip::Protocols::InteractionModel::Status emAfReadOrWriteAttribute(const EmberAfAttributeSearchRecord * attRecord,
const EmberAfAttributeMetadata ** metadata, uint8_t * buffer,
uint16_t readLength, bool write);
Expand Down
16 changes: 15 additions & 1 deletion src/app/util/attribute-storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,8 @@ static void shutdownEndpoint(EmberAfDefinedEndpoint * definedEndpoint)
const EmberAfEndpointType * epType = definedEndpoint->endpointType;
for (clusterIndex = 0; clusterIndex < epType->clusterCount; clusterIndex++)
{
const EmberAfCluster * cluster = &(epType->cluster[clusterIndex]);
const EmberAfCluster * cluster = &(epType->cluster[clusterIndex]);
emberAfClusterShutdownCallback(definedEndpoint->endpoint, cluster->clusterId);
EmberAfGenericClusterFunction f = emberAfFindClusterFunction(cluster, MATTER_CLUSTER_FLAG_SHUTDOWN_FUNCTION);
if (f != nullptr)
{
Expand All @@ -503,6 +504,19 @@ void emAfCallInits()
}
}

// Calls the shutdown functions.
void emAfCallShutdowns()
{
uint16_t index;
for (index = 0; index < emberAfEndpointCount(); index++)
{
if (emberAfEndpointIndexIsEnabled(index))
{
shutdownEndpoint(&(emAfEndpoints[index]));
}
}
}

// Returns the pointer to metadata, or null if it is not found
const EmberAfAttributeMetadata * emberAfLocateAttributeMetadata(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId)
{
Expand Down
11 changes: 11 additions & 0 deletions src/app/util/generic-callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@
*/
void emberAfClusterInitCallback(chip::EndpointId endpoint, chip::ClusterId clusterId);

/** @brief Cluster Shutdown
*
* This function is called when a specific cluster is shutdown. It gives the
* application an opportunity to take care of cluster shutdown procedures.
* It is called exactly once for each endpoint where cluster is present.
*
* @param endpoint Ver.: always
* @param clusterId Ver.: always
*/
void emberAfClusterShutdownCallback(chip::EndpointId endpoint, chip::ClusterId clusterId);

/** @brief Attribute Read Access
*
* This function is called whenever the Application Framework needs to check
Expand Down
70 changes: 70 additions & 0 deletions src/app/util/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ void emberAfInit()
emAfCallInits();
}

// ****************************************
// Shutdown Clusters
// ****************************************
void emberAfShutdown()
{
emAfCallShutdowns();
MATTER_PLUGINS_SHUTDOWN
}

// Cluster init functions that don't have a cluster implementation to define
// them in.
void MatterBallastConfigurationPluginServerInitCallback() {}
Expand Down Expand Up @@ -143,6 +152,67 @@ void MatterCommodityPricePluginServerInitCallback() {}
void MatterElectricalGridConditionsPluginServerInitCallback() {}
void MatterSoilMeasurementPluginServerInitCallback() {}

// Cluster shutdown functions that don't have a cluster implementation to define
// them in.
void MatterBallastConfigurationPluginServerShutdownCallback() {}
void MatterBooleanStatePluginServerShutdownCallback() {}
void MatterRelativeHumidityMeasurementPluginServerShutdownCallback() {}
void MatterIlluminanceMeasurementPluginServerShutdownCallback() {}
void MatterBinaryInputBasicPluginServerShutdownCallback() {}
void MatterPressureMeasurementPluginServerShutdownCallback() {}
void MatterTemperatureMeasurementPluginServerShutdownCallback() {}
void MatterFlowMeasurementPluginServerShutdownCallback() {}
void MatterThermostatUserInterfaceConfigurationPluginServerShutdownCallback() {}
void MatterBridgedDeviceBasicInformationPluginServerShutdownCallback() {}
void MatterPowerConfigurationPluginServerShutdownCallback() {}
void MatterPowerProfilePluginServerShutdownCallback() {}
void MatterPulseWidthModulationPluginServerShutdownCallback() {}
void MatterAlarmsPluginServerShutdownCallback() {}
void MatterTimePluginServerShutdownCallback() {}
void MatterAclPluginServerShutdownCallback() {}
void MatterPollControlPluginServerShutdownCallback() {}
void MatterProxyValidPluginServerShutdownCallback() {}
void MatterProxyDiscoveryPluginServerShutdownCallback() {}
void MatterProxyConfigurationPluginServerShutdownCallback() {}
void MatterFanControlPluginServerShutdownCallback() {}
void MatterActivatedCarbonFilterMonitoringPluginServerShutdownCallback() {}
void MatterHepaFilterMonitoringPluginServerShutdownCallback() {}
void MatterAirQualityPluginServerShutdownCallback() {}
void MatterCarbonMonoxideConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterCarbonDioxideConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterFormaldehydeConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterNitrogenDioxideConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterOzoneConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterPm10ConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterPm1ConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterPm25ConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterRadonConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterTotalVolatileOrganicCompoundsConcentrationMeasurementPluginServerShutdownCallback() {}
void MatterRvcRunModePluginServerShutdownCallback() {}
void MatterRvcCleanModePluginServerShutdownCallback() {}
void MatterDishwasherModePluginServerShutdownCallback() {}
void MatterLaundryWasherModePluginServerShutdownCallback() {}
void MatterRefrigeratorAndTemperatureControlledCabinetModePluginServerShutdownCallback() {}
void MatterOperationalStatePluginServerShutdownCallback() {}
void MatterRvcOperationalStatePluginServerShutdownCallback() {}
void MatterOvenModePluginServerShutdownCallback() {}
void MatterOvenCavityOperationalStatePluginServerShutdownCallback() {}
void MatterDishwasherAlarmPluginServerShutdownCallback() {}
void MatterMicrowaveOvenModePluginServerShutdownCallback() {}
void MatterDeviceEnergyManagementModePluginServerShutdownCallback() {}
void MatterEnergyEvseModePluginServerShutdownCallback() {}
void MatterPowerTopologyPluginServerShutdownCallback() {}
void MatterElectricalEnergyMeasurementPluginServerShutdownCallback() {}
void MatterElectricalPowerMeasurementPluginServerShutdownCallback() {}
void MatterServiceAreaPluginServerShutdownCallback() {}
void MatterWaterHeaterManagementPluginServerShutdownCallback() {}
void MatterWaterHeaterModePluginServerShutdownCallback() {}
void MatterMeterIdentificationPluginServerShutdownCallback() {}
void MatterClosureDimensionPluginServerShutdownCallback() {}
void MatterElectricalGridConditionsPluginServerShutdownCallback() {}
void MatterCommodityPricePluginServerShutdownCallback() {}
void MatterSoilMeasurementPluginServerShutdownCallback() {}

bool emberAfContainsAttribute(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId)
{
return (emberAfGetServerAttributeIndexByAttributeId(endpoint, clusterId, attributeId) != UINT16_MAX);
Expand Down
1 change: 1 addition & 0 deletions src/app/util/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

void emberAfInit();

void emberAfShutdown();
/**
* Retrieves the difference between the two passed values.
* This function assumes that the two values have the same endianness.
Expand Down
1 change: 1 addition & 0 deletions src/controller/EmptyDataModelHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
#include <app/util/DataModelHandler.h>

void InitDataModelHandler() {}
void ShutdownDataModelHandler() {}
4 changes: 3 additions & 1 deletion src/controller/tests/TestServerCommandDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,10 @@ class DispatchTestDataModel : public CodegenDataModelProvider

protected:
// Since the current unit tests do not involve any cluster implementations, we override InitDataModelForTesting
// to do nothing, thereby preventing calls to the Ember-specific InitDataModelHandler.
// ShutdownDataModelForTesting to do nothing, thereby preventing calls to the Ember-specific InitDataModelHandler
// and ShutdownDataModelHandler.
void InitDataModelForTesting() override {}
void ShutdownDataModelForTesting() override {}
};

class TestServerCommandDispatch : public chip::Test::AppContext
Expand Down
3 changes: 2 additions & 1 deletion src/controller/tests/data_model/DataModelFixtures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ using namespace chip::app::Clusters;
using namespace chip::app::Clusters::UnitTesting;
using namespace chip::Protocols;

// Mock function for linking
// Mock functions for linking
void InitDataModelHandler() {}
void ShutdownDataModelHandler() {}

namespace chip {
namespace app {
Expand Down
1 change: 1 addition & 0 deletions src/credentials/FabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,7 @@ void FabricTable::Shutdown()
delegate->next = nullptr;
delegate = temp;
}
mDelegateListRoot = nullptr;

RevertPendingFabricData();
for (FabricInfo & fabricInfo : mStates)
Expand Down
8 changes: 8 additions & 0 deletions src/darwin/Framework/CHIP/ServerEndpoint/MTRIMDispatch.mm
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId)
// clusters dont use it.
}

void emberAfClusterShutdownCallback(EndpointId endpoint, ClusterId clusterId)
{
assertChipStackLockedByCurrentThread();

// No-op: Descriptor and OTA do not need this, and our client-defined
// clusters dont use it.
}

Protocols::InteractionModel::Status emAfWriteAttributeExternal(const ConcreteAttributePath & path,
const EmberAfWriteDataInput & input)
{
Expand Down
2 changes: 2 additions & 0 deletions src/darwin/Framework/CHIP/app/PluginApplicationCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@
*/

void MatterDescriptorPluginServerInitCallback();
void MatterDescriptorPluginServerShutdownCallback();

#define MATTER_PLUGINS_INIT MatterDescriptorPluginServerInitCallback();
#define MATTER_PLUGINS_SHUTDOWN MatterDescriptorPluginServerShutdownCallback();
Loading
Loading