Skip to content
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

Refactor SafeAttributePersistenceProvider and AttributePersistenceProvider to move ember-specific bits to codegendatamodelprovider #36476

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4b94904
Move persistence providers code into util since they depend on ember.
andreilitvin Nov 12, 2024
c26c9f0
Fix up more includes
andreilitvin Nov 12, 2024
64d9acf
Restyled by clang-format
restyled-commits Nov 12, 2024
80e826b
Fix up qpg build
andreilitvin Nov 12, 2024
4fe03be
Also fix nrfconnect deferred attribute persistence use
andreilitvin Nov 12, 2024
6ffb911
Fix path
andreilitvin Nov 12, 2024
f387b7b
Add persistence to esp32 CMakeLists.txt
andy31415 Nov 12, 2024
964cf5b
Take out ember and non-ember bits of the persistence provider
andy31415 Nov 12, 2024
c0ee99d
Persistence test actually only ever tests the save side of the persis…
andy31415 Nov 12, 2024
7d421d0
Start using Safe and Attribute persistence in a separate way. Still n…
andy31415 Nov 12, 2024
dfbf1d5
A bit of work to make Server init decoupled ember specific persistenc…
andy31415 Nov 12, 2024
770d7b2
Some compile fixes
andy31415 Nov 12, 2024
498268e
Make all applications provide a datamodel provider
andy31415 Nov 12, 2024
fd485fe
CI passes. We probably have to fix tons of dependencies still
andy31415 Nov 12, 2024
3e91e55
Restyled by clang-format
restyled-commits Nov 12, 2024
59de647
Fix efr32 build
andy31415 Nov 13, 2024
4cfc7a2
Fix qpg and nrf deferred persistence providers
andy31415 Nov 13, 2024
cd67f5a
Restyle
andy31415 Nov 13, 2024
9b100f5
Make attribute persistence part of libchip as it is generic and code …
andy31415 Nov 13, 2024
944e910
Fix android dependency
andy31415 Nov 13, 2024
efc0391
Fix up ordering of startup in Server.cpp
andy31415 Nov 13, 2024
9790c14
Restyle
andy31415 Nov 13, 2024
9f4da18
Update placement of storage int again, just before fabric so order is…
andy31415 Nov 13, 2024
b2f16b7
Merge branch 'master' into move_persistence_provider
andy31415 Nov 14, 2024
66861cf
Merge branch 'move_persistence_provider' into more_persistence_provid…
andy31415 Nov 14, 2024
22e9875
Merge branch 'master' into more_persistence_provider_refactor
andy31415 Nov 18, 2024
9388a04
Fix wrong paste text
andy31415 Nov 18, 2024
43372b9
Remove redundant previs for CodegenDataModelProviderInstance
andy31415 Nov 18, 2024
2483cd7
One more path update
andy31415 Nov 18, 2024
76272de
Merge branch 'master' into more_persistence_provider_refactor
andreilitvin Nov 19, 2024
aa88e5d
Undo examples change: looking to undo the server init provider argume…
andreilitvin Nov 19, 2024
a7be8c3
Fix includes
andreilitvin Nov 19, 2024
e325098
Revert more codegendatamodelprovider usage
andreilitvin Nov 19, 2024
35db533
Remove more usage of dataModelProvider input. This should now be a cl…
andreilitvin Nov 19, 2024
7cad7d6
Fix include
andreilitvin Nov 19, 2024
b4f465f
Fix up logic for Deferred persistence providers
andreilitvin Nov 19, 2024
60d388d
Merge branch 'master' into more_persistence_provider_refactor
andy31415 Nov 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions examples/lighting-app/nrfconnect/main/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,8 @@ chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;
// be written, so it must live so long as the DeferredAttributePersistenceProvider object.
DeferredAttribute gCurrentLevelPersister(ConcreteAttributePath(kLightEndpointId, Clusters::LevelControl::Id,
Clusters::LevelControl::Attributes::CurrentLevel::Id));
DeferredAttributePersistenceProvider gDeferredAttributePersister(Server::GetInstance().GetDefaultAttributePersister(),
Span<DeferredAttribute>(&gCurrentLevelPersister, 1),
System::Clock::Milliseconds32(5000));

DeferredAttributePersistenceProvider gDeferredAttributePersister;

#ifdef CONFIG_CHIP_CRYPTO_PSA
chip::Crypto::PSAOperationalKeystore sPSAOperationalKeystore{};
Expand Down Expand Up @@ -278,7 +277,13 @@ CHIP_ERROR AppTask::Init()

gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage());
chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
app::SetAttributePersistenceProvider(&gDeferredAttributePersister);

// Server will initialize a persistence provider
VerifyOrDie(GetAttributePersistenceProvider() != nullptr);
VerifyOrDie(gDeferredAttributePersister.Init(*GetAttributePersistenceProvider(),
Span<DeferredAttribute>(&gCurrentLevelPersister, 1),
System::Clock::Milliseconds32(5000)) == CHIP_NO_ERROR);
SetAttributePersistenceProvider(&gDeferredAttributePersister);

ConfigurationMgr().LogDeviceConfig();
PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE));
Expand Down
11 changes: 7 additions & 4 deletions examples/lighting-app/qpg/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <app/server/Dnssd.h>
#include <app/server/Server.h>
#include <app/util/attribute-storage.h>
#include <app/util/persistence/AttributePersistenceProvider.h>
#include <lib/support/TypeTraits.h>

#include <app/util/persistence/DeferredAttributePersistenceProvider.h>
Expand Down Expand Up @@ -113,9 +114,7 @@ DeferredAttribute gPersisters[] = {

};

DeferredAttributePersistenceProvider gDeferredAttributePersister(Server::GetInstance().GetDefaultAttributePersister(),
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
Span<DeferredAttribute>(gPersisters, 3),
System::Clock::Milliseconds32(5000));
DeferredAttributePersistenceProvider gDeferredAttributePersister;

/**********************************************************
* Identify Callbacks
Expand Down Expand Up @@ -277,7 +276,11 @@ void AppTask::InitServer(intptr_t arg)

chip::Server::GetInstance().Init(initParams);

app::SetAttributePersistenceProvider(&gDeferredAttributePersister);
// Server will initialize a persistence provider
VerifyOrDie(GetAttributePersistenceProvider() != nullptr);
VerifyOrDie(gDeferredAttributePersister.Init(*GetAttributePersistenceProvider(), Span<DeferredAttribute>(gPersisters, 3),
System::Clock::Milliseconds32(5000)) == CHIP_NO_ERROR);
SetAttributePersistenceProvider(&gDeferredAttributePersister);

#if CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY
chip::app::DnssdServer::Instance().SetExtendedDiscoveryTimeoutSecs(extDiscTimeoutSecs);
Expand Down
5 changes: 1 addition & 4 deletions src/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,7 @@ if (chip_build_tests) {
}

if (chip_device_platform != "efr32") {
tests += [
"${chip_root}/src/app/tests",
"${chip_root}/src/app/util/persistence/tests",
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
]
tests += [ "${chip_root}/src/app/tests" ]

# Disabled for EFR32 because _open is not implemented.
# https://github.com/project-chip/connectedhomeip/issues/35624
Expand Down
6 changes: 5 additions & 1 deletion src/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,10 @@ source_set("command-handler-impl") {
}

source_set("attribute-persistence") {
sources = [ "SafeAttributePersistenceProvider.h" ]
sources = [
"SafeAttributePersistenceProvider.cpp",
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
"SafeAttributePersistenceProvider.h",
]

public_deps = [
":paths",
Expand Down Expand Up @@ -441,6 +444,7 @@ static_library("app") {
public_deps = [
":app_config",
":attribute-access",
":attribute-persistence",
":constants",
":global-attributes",
":interaction-model",
Expand Down
1 change: 1 addition & 0 deletions src/app/InteractionModelEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ void InteractionModelEngine::Shutdown()

mpCASESessionMgr = nullptr;

SetDataModelProvider(nullptr);
//
// We _should_ be clearing these out, but doing so invites a world
// of trouble. #21233 tracks fixing the underlying assumptions to make
Expand Down
81 changes: 81 additions & 0 deletions src/app/SafeAttributePersistenceProvider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
* Copyright (c) 2024 Project CHIP Authors
*
* 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 <app/SafeAttributePersistenceProvider.h>

#include <lib/core/CHIPError.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>

namespace chip {
namespace app {

CHIP_ERROR SafeAttributePersistenceProvider::KeyWriteValue(const StorageKeyName & aKey, const ByteSpan & aValue)
{
VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);

// TODO: we may want to have a small cache for values that change a lot, so
// we only write them once a bunch of changes happen or on timer or
// shutdown.
if (!CanCastTo<uint16_t>(aValue.size()))
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
return mStorage->SyncSetKeyValue(aKey.KeyName(), aValue.data(), static_cast<uint16_t>(aValue.size()));
}

CHIP_ERROR SafeAttributePersistenceProvider::KeyReadValue(const StorageKeyName & aKey, MutableByteSpan & aValue)
{
VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);

uint16_t size = static_cast<uint16_t>(std::min(aValue.size(), static_cast<size_t>(UINT16_MAX)));
ReturnErrorOnFailure(mStorage->SyncGetKeyValue(aKey.KeyName(), aValue.data(), size));
aValue.reduce_size(size);
return CHIP_NO_ERROR;
}

CHIP_ERROR SafeAttributePersistenceProvider::SafeWriteValue(const ConcreteAttributePath & aPath, const ByteSpan & aValue)
{
return KeyWriteValue(DefaultStorageKeyAllocator::SafeAttributeValue(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId),
aValue);
}

CHIP_ERROR SafeAttributePersistenceProvider::SafeReadValue(const ConcreteAttributePath & aPath, MutableByteSpan & aValue)
{
return KeyReadValue(DefaultStorageKeyAllocator::SafeAttributeValue(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId),
aValue);
}

namespace {

SafeAttributePersistenceProvider * gSafeAttributeSaver = nullptr;

} // anonymous namespace

SafeAttributePersistenceProvider * GetSafeAttributePersistenceProvider()
{
return gSafeAttributeSaver;
}

void SetSafeAttributePersistenceProvider(SafeAttributePersistenceProvider * aProvider)
{
if (aProvider != nullptr)
{
gSafeAttributeSaver = aProvider;
}
}

} // namespace app
} // namespace chip
32 changes: 29 additions & 3 deletions src/app/SafeAttributePersistenceProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
#include <app/util/attribute-metadata.h>
#include <lib/support/BufferReader.h>
#include <lib/support/BufferWriter.h>
#include <lib/support/DefaultStorageKeyAllocator.h>
#include <lib/support/Span.h>

#include <cstring>
#include <inttypes.h>

namespace chip {
namespace app {
Expand All @@ -39,6 +39,19 @@ class SafeAttributePersistenceProvider
virtual ~SafeAttributePersistenceProvider() = default;
SafeAttributePersistenceProvider() = default;

// Passed-in storage must outlive this object.
CHIP_ERROR Init(PersistentStorageDelegate * storage)
{
if (storage == nullptr)
{
return CHIP_ERROR_INVALID_ARGUMENT;
}
mStorage = storage;
return CHIP_NO_ERROR;
}

void Shutdown() {}

// The following API provides helper functions to simplify the access of commonly used types.
// The API may not be complete.
// Currently implemented write and read types are: bool, uint8_t, uint16_t, uint32_t, unit64_t and
Expand Down Expand Up @@ -141,7 +154,7 @@ class SafeAttributePersistenceProvider
* @param [in] aPath the attribute path for the data being written.
* @param [in] aValue the data to write. The value will be stored as-is.
*/
virtual CHIP_ERROR SafeWriteValue(const ConcreteAttributePath & aPath, const ByteSpan & aValue) = 0;
virtual CHIP_ERROR SafeWriteValue(const ConcreteAttributePath & aPath, const ByteSpan & aValue);
Copy link
Contributor

@bzbarsky-apple bzbarsky-apple Nov 20, 2024

Choose a reason for hiding this comment

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

No, the whole point of SafeAttributePersistenceProvider is that it's an interface, which can be implemented however is convenient to the application, no? In particular, it might not be implemented on top of PersistentStorageDelegate at all (and probably shouldn't be; constraints on PersistentStorageDelegate mean that in some situations you in fact cannot build SafeAttributePersistenceProvider on top of PersistentStorageDelegate).

I'm stopping here, since this seems like a pretty fundamental issue. So just to be clear:

  1. This is meant to be a pure interface.
  2. Some specific implementations of this interface might exist, and the SDK should provide a default one to make things easy for people who want to use that default.
  3. The implementation to actually use should be injected. I know that's not what we do now, and Server just hardcodes a DefaultAttributePersistenceProvider, but that's a TODO/bug to fix, not something to reify in our API surface.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Following up offline to figure out an approach here. This is what we have today (has a very organic-grown feel to it):

image


/**
* Read an attribute value as a raw sequence of bytes from non-volatile memory.
Expand All @@ -154,7 +167,20 @@ class SafeAttributePersistenceProvider
* @retval CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND if no stored value exists for the attribute
* @retval CHIP_ERROR_BUFFER_TOO_SMALL aValue.size() is too small to hold the value.
*/
virtual CHIP_ERROR SafeReadValue(const ConcreteAttributePath & aPath, MutableByteSpan & aValue) = 0;
virtual CHIP_ERROR SafeReadValue(const ConcreteAttributePath & aPath, MutableByteSpan & aValue);

/**
* Key-based I/O. Prefer using the `Safe` calls above
*/
CHIP_ERROR KeyWriteValue(const StorageKeyName & aKey, const ByteSpan & aValue);

/**
* Key-based I/O. Prefer using the `Safe` calls above
*/
CHIP_ERROR KeyReadValue(const StorageKeyName & aKey, MutableByteSpan & aValue);

protected:
PersistentStorageDelegate * mStorage;
};

/**
Expand Down
32 changes: 32 additions & 0 deletions src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
#include <app/ConcreteCommandPath.h>
#include <app/EventPathParams.h>
#include <app/RequiredPrivilege.h>
#include <app/SafeAttributePersistenceProvider.h>
#include <app/data-model-provider/MetadataTypes.h>
#include <app/data-model-provider/Provider.h>
#include <app/util/IMClusterCommandHandler.h>
#include <app/util/af-types.h>
#include <app/util/attribute-storage.h>
#include <app/util/endpoint-config-api.h>
#include <app/util/persistence/AttributePersistenceProvider.h>
#include <app/util/persistence/DefaultAttributePersistenceProvider.h>
#include <lib/core/CHIPError.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/CodeUtils.h>
Expand Down Expand Up @@ -300,8 +303,37 @@ unsigned FindNextDeviceTypeIndex(Span<const EmberAfDeviceType> types, const Data

const ConcreteCommandPath kInvalidCommandPath(kInvalidEndpointId, kInvalidClusterId, kInvalidCommandId);

// Ember requires a persistence provider
DefaultAttributePersistenceProvider gDefaultAttributePersistenceProvider;

} // namespace

CHIP_ERROR CodegenDataModelProvider::Startup(DataModel::InteractionModelContext context)
{
ReturnErrorOnFailure(DataModel::Provider::Startup(context));

// Ember/codegen requires a persistence provider. Ensure one is set.
if (GetAttributePersistenceProvider() == nullptr)
{
ReturnErrorOnFailure(gDefaultAttributePersistenceProvider.Init(GetSafeAttributePersistenceProvider()));
SetAttributePersistenceProvider(&gDefaultAttributePersistenceProvider);
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
}

return CHIP_NO_ERROR;
}

CHIP_ERROR CodegenDataModelProvider::Shutdown()
{
Reset();

if (GetAttributePersistenceProvider() == &gDefaultAttributePersistenceProvider)
{
gDefaultAttributePersistenceProvider.Shutdown();
// We cannot actually reset it as `SetAttributePersistenceProvider` ignores nullptr
}
return CHIP_NO_ERROR;
}

std::optional<CommandId> CodegenDataModelProvider::EmberCommandListIterator::First(const CommandId * list)
{
VerifyOrReturnValue(list != nullptr, std::nullopt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,8 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider
}

/// Generic model implementations
CHIP_ERROR Shutdown() override
{
Reset();
return CHIP_NO_ERROR;
}
CHIP_ERROR Startup(DataModel::InteractionModelContext context) override;
CHIP_ERROR Shutdown() override;

DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
AttributeValueEncoder & encoder) override;
Expand Down
1 change: 1 addition & 0 deletions src/app/codegen-data-model-provider/model.gni
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ codegen_data_model_PUBLIC_DEPS = [
"${chip_root}/src/app/common:attribute-type",
"${chip_root}/src/app/data-model-provider",
"${chip_root}/src/app/codegen-data-model-provider:instance-header",
"${chip_root}/src/app/util/persistence",
]
11 changes: 5 additions & 6 deletions src/app/data-model-provider/Provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@
*/
#pragma once

#include "access/SubjectDescriptor.h"
#include "app/EventPathParams.h"
#include "lib/core/CHIPError.h"
#include <lib/core/TLVReader.h>
#include <lib/core/TLVWriter.h>

#include <access/SubjectDescriptor.h>
#include <app/AttributeValueDecoder.h>
#include <app/AttributeValueEncoder.h>
#include <app/CommandHandler.h>
#include <app/EventPathParams.h>
#include <lib/core/CHIPError.h>
#include <lib/core/TLVReader.h>
#include <lib/core/TLVWriter.h>

#include <app/data-model-provider/ActionReturnStatus.h>
#include <app/data-model-provider/Context.h>
Expand Down
15 changes: 11 additions & 4 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,16 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams)

// Set up attribute persistence before we try to bring up the data model
// handler.
SuccessOrExit(err = mAttributePersister.Init(mDeviceStorage));
SetAttributePersistenceProvider(&mAttributePersister);
SetSafeAttributePersistenceProvider(&mAttributePersister);
SuccessOrExit(err = mSafeAttributePersister.Init(mDeviceStorage));
SetSafeAttributePersistenceProvider(&mSafeAttributePersister);

// Temporary setup until a full ember decoupling (including the InitDataModelHandler) is done outside
// of app code:
// - InitDataModelHandler uses ember init (so needs a data model provider)
// - Ember requires a persistence provider which is available currently from CodegenDataModelProvider, so
// ensure the codegen data model provider is initialized.
// TODO: this should eventually become a `SetDataModelProvider` that is based on `initParams`
(void) chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider();

// SetDataModelProvider() actually initializes/starts the provider. We need
// to preserve the following ordering guarantees:
Expand Down Expand Up @@ -665,7 +672,7 @@ void Server::Shutdown()
}
mICDManager.Shutdown();
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
mAttributePersister.Shutdown();

// TODO(16969): Remove chip::Platform::MemoryInit() call from Server class, it belongs to outer code
chip::Platform::MemoryShutdown();
}
Expand Down
Loading
Loading