diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index 34e97069256bc6..eb873bdc02b8dc 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -118,7 +118,42 @@ DataVersion fixedEndpointDataVersions[ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT]; #define endpointTypeMacro(x) (&(generatedEmberAfEndpointTypes[fixedEmberAfEndpointTypes[x]])) #endif -app::AttributeAccessInterface * gAttributeAccessOverrides = nullptr; +AttributeAccessInterface * gAttributeAccessOverrides = nullptr; + +// shouldUnregister returns true if the given AttributeAccessInterface should be +// unregistered. +template +void UnregisterMatchingAttributeAccessInterfaces(F shouldUnregister) +{ + AttributeAccessInterface * prev = nullptr; + AttributeAccessInterface * cur = gAttributeAccessOverrides; + while (cur) + { + AttributeAccessInterface * next = cur->GetNext(); + if (shouldUnregister(cur)) + { + // Remove it from the list + if (prev) + { + prev->SetNext(next); + } + else + { + gAttributeAccessOverrides = next; + } + + cur->SetNext(nullptr); + + // Do not change prev in this case. + } + else + { + prev = cur; + } + cur = next; + } +} + } // anonymous namespace // Initial configuration @@ -383,33 +418,8 @@ static void shutdownEndpoint(EmberAfDefinedEndpoint * definedEndpoint) // Clear out any attribute access overrides registered for this // endpoint. - app::AttributeAccessInterface * prev = nullptr; - app::AttributeAccessInterface * cur = gAttributeAccessOverrides; - while (cur) - { - app::AttributeAccessInterface * next = cur->GetNext(); - if (cur->MatchesEndpoint(definedEndpoint->endpoint)) - { - // Remove it from the list - if (prev) - { - prev->SetNext(next); - } - else - { - gAttributeAccessOverrides = next; - } - - cur->SetNext(nullptr); - - // Do not change prev in this case. - } - else - { - prev = cur; - } - cur = next; - } + UnregisterMatchingAttributeAccessInterfaces( + [endpoint = definedEndpoint->endpoint](AttributeAccessInterface * entry) { return entry->MatchesEndpoint(endpoint); }); } // Calls the init functions. @@ -1378,7 +1388,7 @@ EmberAfGenericClusterFunction emberAfFindClusterFunction(const EmberAfCluster * return cluster->functions[functionIndex]; } -bool registerAttributeAccessOverride(app::AttributeAccessInterface * attrOverride) +bool registerAttributeAccessOverride(AttributeAccessInterface * attrOverride) { for (auto * cur = gAttributeAccessOverrides; cur; cur = cur->GetNext()) { @@ -1393,6 +1403,11 @@ bool registerAttributeAccessOverride(app::AttributeAccessInterface * attrOverrid return true; } +void unregisterAttributeAccessOverride(AttributeAccessInterface * attrOverride) +{ + UnregisterMatchingAttributeAccessInterfaces([attrOverride](AttributeAccessInterface * entry) { return entry == attrOverride; }); +} + namespace chip { namespace app { app::AttributeAccessInterface * GetAttributeAccessOverride(EndpointId endpointId, ClusterId clusterId) diff --git a/src/app/util/attribute-storage.h b/src/app/util/attribute-storage.h index da83bf1840e27d..91a41570fb84c5 100644 --- a/src/app/util/attribute-storage.h +++ b/src/app/util/attribute-storage.h @@ -248,13 +248,20 @@ chip::Optional emberAfGetServerAttributeIdByIndex(chip::Endpo uint16_t attributeIndex); /** - * Register an attribute access override. It will remain registered until - * the endpoint it's registered for is disabled (or until shutdown if it's - * registered for all endpoints). Registration will fail if there is an - * already-registered override for the same set of attributes. + * Register an attribute access override. It will remain registered until the + * endpoint it's registered for is disabled (or until shutdown if it's + * registered for all endpoints) or until it is explicitly unregistered. + * Registration will fail if there is an already-registered override for the + * same set of attributes. * * @return false if there is an existing override that the new one would * conflict with. In this case the override is not registered. * @return true if registration was successful. */ bool registerAttributeAccessOverride(chip::app::AttributeAccessInterface * attrOverride); + +/** + * Unregister an attribute access override (for example if the object + * implementing AttributeAccessInterface is being destroyed). + */ +void unregisterAttributeAccessOverride(chip::app::AttributeAccessInterface * attrOverride);