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

Allow specifying per-controller OTA delegates in Darwin.framework. #29014

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Allow specifying per-controller OTA delegates in Darwin.framework.
Review note: the delegate-validation code in initWithFactory just moved there
from startControllerFactory, with no real changes to it other than changing what
it returns on error.
  • Loading branch information
bzbarsky-apple committed Sep 1, 2023
commit 54d6b9149a7cad30efdc50fd305be9f1a1ea651f
54 changes: 54 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
queue:(dispatch_queue_t)queue
storageDelegate:(id<MTRDeviceControllerStorageDelegate> _Nullable)storageDelegate
storageDelegateQueue:(dispatch_queue_t _Nullable)storageDelegateQueue
otaProviderDelegate:(id<MTROTAProviderDelegate> _Nullable)otaProviderDelegate
otaProviderDelegateQueue:(dispatch_queue_t _Nullable)otaProviderDelegateQueue
uniqueIdentifier:(NSUUID *)uniqueIdentifier
{
if (self = [super init]) {
Expand All @@ -143,6 +145,58 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
}
}

// Ensure the otaProviderDelegate, if any, is valid.
if (otaProviderDelegate == nil && otaProviderDelegateQueue != nil) {
MTR_LOG_ERROR("Must have otaProviderDelegate when we have otaProviderDelegateQueue");
return nil;
}

if (otaProviderDelegate != nil && otaProviderDelegateQueue == nil) {
MTR_LOG_ERROR("Must have otaProviderDelegateQueue when we have otaProviderDelegate");
return nil;
}

if (otaProviderDelegate != nil) {
if (![otaProviderDelegate respondsToSelector:@selector(handleQueryImageForNodeID:controller:params:completion:)]
&& ![otaProviderDelegate respondsToSelector:@selector(handleQueryImageForNodeID:
controller:params:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleQueryImageForNodeID");
return nil;
}
if (![otaProviderDelegate respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completion:)]
&& ![otaProviderDelegate
respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleApplyUpdateRequestForNodeID");
return nil;
}
if (![otaProviderDelegate respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:
controller:params:completion:)]
&& ![otaProviderDelegate
respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:controller:params:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleNotifyUpdateAppliedForNodeID");
return nil;
}
if (![otaProviderDelegate respondsToSelector:@selector
(handleBDXTransferSessionBeginForNodeID:controller:fileDesignator:offset:completion:)]
&& ![otaProviderDelegate respondsToSelector:@selector
(handleBDXTransferSessionBeginForNodeID:
controller:fileDesignator:offset:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXTransferSessionBeginForNodeID");
return nil;
}
if (![otaProviderDelegate
respondsToSelector:@selector(handleBDXQueryForNodeID:controller:blockSize:blockIndex:bytesToSkip:completion:)]
&& ![otaProviderDelegate
respondsToSelector:@selector(handleBDXQueryForNodeID:
controller:blockSize:blockIndex:bytesToSkip:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXQueryForNodeID");
return nil;
}
}

_otaProviderDelegate = otaProviderDelegate;
_otaProviderDelegateQueue = otaProviderDelegateQueue;

_chipWorkQueue = queue;
_factory = factory;
_deviceMapLock = OS_UNFAIR_LOCK_INIT;
Expand Down
103 changes: 43 additions & 60 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
static NSString * const kErrorControllerFactoryInit = @"Init failure while initializing controller factory";
static NSString * const kErrorKeystoreInit = @"Init failure while initializing persistent storage keystore";
static NSString * const kErrorCertStoreInit = @"Init failure while initializing persistent storage operational certificate store";
static NSString * const kErrorOtaProviderInit = @"Init failure while creating an OTA provider delegate";
static NSString * const kErrorSessionKeystoreInit = @"Init failure while initializing session keystore";

static bool sExitHandlerRegistered = false;
Expand Down Expand Up @@ -123,6 +122,9 @@ @interface MTRDeviceControllerFactory ()
// D. Locking around reads not from the Matter queue is OK but not required.
@property (nonatomic, readonly) os_unfair_lock controllersLock;

@property (nonatomic, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
@property (nonatomic, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;

- (BOOL)findMatchingFabric:(FabricTable &)fabricTable
params:(MTRDeviceControllerStartupParams *)params
fabric:(const FabricInfo * _Nullable * _Nonnull)fabric;
Expand Down Expand Up @@ -289,9 +291,15 @@ - (void)cleanupInitObjects

- (void)cleanupStartupObjects
{
if (_otaProviderDelegateBridge) {
delete _otaProviderDelegateBridge;
_otaProviderDelegateBridge = nullptr;
// Make sure the deinit order here is the reverse of the init order in
// startControllerFactory:
_certificationDeclarationCertificates = nil;
_productAttestationAuthorityCertificates = nil;

if (_opCertStore) {
_opCertStore->Finish();
delete _opCertStore;
_opCertStore = nullptr;
}

if (_keystore) {
Expand All @@ -300,11 +308,12 @@ - (void)cleanupStartupObjects
_keystore = nullptr;
}

if (_opCertStore) {
_opCertStore->Finish();
delete _opCertStore;
_opCertStore = nullptr;
if (_otaProviderDelegateBridge) {
delete _otaProviderDelegateBridge;
_otaProviderDelegateBridge = nullptr;
}
_otaProviderDelegateQueue = nil;
_otaProviderDelegate = nil;

if (_sessionResumptionStorage) {
delete _sessionResumptionStorage;
Expand Down Expand Up @@ -412,57 +421,12 @@ - (BOOL)startControllerFactory:(MTRDeviceControllerFactoryParams *)startupParams
return;
}

if (startupParams.otaProviderDelegate) {
if (![startupParams.otaProviderDelegate respondsToSelector:@selector(handleQueryImageForNodeID:
controller:params:completion:)]
&& ![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleQueryImageForNodeID:controller:params:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleQueryImageForNodeID");
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
return;
}
if (![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completion:)]
&& ![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleApplyUpdateRequestForNodeID");
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
return;
}
if (![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:controller:params:completion:)]
&& ![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:controller:params:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleNotifyUpdateAppliedForNodeID");
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
return;
}
if (![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleBDXTransferSessionBeginForNodeID:
controller:fileDesignator:offset:completion:)]
&& ![startupParams.otaProviderDelegate
respondsToSelector:@selector
(handleBDXTransferSessionBeginForNodeID:controller:fileDesignator:offset:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXTransferSessionBeginForNodeID");
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
return;
}
if (![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleBDXQueryForNodeID:controller:blockSize:blockIndex:bytesToSkip:completion:)]
&& ![startupParams.otaProviderDelegate
respondsToSelector:@selector(handleBDXQueryForNodeID:
controller:blockSize:blockIndex:bytesToSkip:completionHandler:)]) {
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXQueryForNodeID");
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
return;
}
_otaProviderDelegateBridge = new MTROTAProviderDelegateBridge(startupParams.otaProviderDelegate);
if (_otaProviderDelegateBridge == nil) {
MTR_LOG_ERROR("Error: %@", kErrorOtaProviderInit);
errorCode = CHIP_ERROR_NO_MEMORY;
return;
}
_otaProviderDelegate = startupParams.otaProviderDelegate;
if (_otaProviderDelegate != nil) {
_otaProviderDelegateQueue = dispatch_queue_create(
"org.csa-iot.matter.framework.otaprovider.workqueue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
}
_otaProviderDelegateBridge = new MTROTAProviderDelegateBridge();

// TODO: Allow passing a different keystore implementation via startupParams.
_keystore = new PersistentStorageOperationalKeystore();
Expand Down Expand Up @@ -594,19 +558,25 @@ - (MTRDeviceController * _Nullable)_startDeviceController:(id)startupParams
return nil;
}

id<MTRDeviceControllerStorageDelegate> storageDelegate;
dispatch_queue_t storageDelegateQueue;
id<MTRDeviceControllerStorageDelegate> _Nullable storageDelegate;
dispatch_queue_t _Nullable storageDelegateQueue;
NSUUID * uniqueIdentifier;
id<MTROTAProviderDelegate> _Nullable otaProviderDelegate;
dispatch_queue_t _Nullable otaProviderDelegateQueue;
if ([startupParams isKindOfClass:[MTRDeviceControllerStartupParameters class]]) {
MTRDeviceControllerStartupParameters * params = startupParams;
storageDelegate = params.storageDelegate;
storageDelegateQueue = params.storageDelegateQueue;
uniqueIdentifier = params.uniqueIdentifier;
otaProviderDelegate = params.otaProviderDelegate;
otaProviderDelegateQueue = params.otaProviderDelegateQueue;
} else if ([startupParams isKindOfClass:[MTRDeviceControllerStartupParams class]]) {
MTRDeviceControllerStartupParams * params = startupParams;
storageDelegate = nil;
storageDelegateQueue = nil;
uniqueIdentifier = params.uniqueIdentifier;
otaProviderDelegate = nil;
otaProviderDelegateQueue = nil;
} else {
MTR_LOG_ERROR("Unknown kind of startup params: %@", startupParams);
return nil;
Expand All @@ -628,10 +598,19 @@ - (MTRDeviceController * _Nullable)_startDeviceController:(id)startupParams
return nil;
}

// Fall back to the factory-wide OTA provider delegate if one is not
// provided in the startup params.
if (otaProviderDelegate == nil) {
otaProviderDelegate = self.otaProviderDelegate;
otaProviderDelegateQueue = self.otaProviderDelegateQueue;
}

// Create the controller, so we start the event loop, since we plan to do
// our fabric table operations there.
auto * controller = [self _createController:storageDelegate
storageDelegateQueue:storageDelegateQueue
otaProviderDelegate:otaProviderDelegate
otaProviderDelegateQueue:otaProviderDelegateQueue
uniqueIdentifier:uniqueIdentifier];
if (controller == nil) {
if (error != nil) {
Expand Down Expand Up @@ -873,6 +852,8 @@ - (MTRDeviceController * _Nullable)createController:(MTRDeviceControllerStartupP

- (MTRDeviceController * _Nullable)_createController:(id<MTRDeviceControllerStorageDelegate> _Nullable)storageDelegate
storageDelegateQueue:(dispatch_queue_t _Nullable)storageDelegateQueue
otaProviderDelegate:(id<MTROTAProviderDelegate> _Nullable)otaProviderDelegate
otaProviderDelegateQueue:(dispatch_queue_t _Nullable)otaProviderDelegateQueue
uniqueIdentifier:(NSUUID *)uniqueIdentifier
{
[self _assertCurrentQueueIsNotMatterQueue];
Expand All @@ -881,6 +862,8 @@ - (MTRDeviceController * _Nullable)_createController:(id<MTRDeviceControllerStor
queue:_chipWorkQueue
storageDelegate:storageDelegate
storageDelegateQueue:storageDelegateQueue
otaProviderDelegate:otaProviderDelegate
otaProviderDelegateQueue:otaProviderDelegateQueue
uniqueIdentifier:uniqueIdentifier];
if (controller == nil) {
MTR_LOG_ERROR("Failed to init controller");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#import <Matter/MTRDefines.h>
#import <Matter/MTRDeviceControllerStorageDelegate.h>
#import <Matter/MTROTAProviderDelegate.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -53,6 +54,12 @@ MTR_NEWLY_AVAILABLE
- (void)setOperationalCertificateIssuer:(id<MTROperationalCertificateIssuer>)operationalCertificateIssuer
queue:(dispatch_queue_t)queue;

/**
* Set an MTROTAProviderDelegate to call (on the provided queue). Only needs to
* be called if this controller should be able to handle OTA for devices.
*/
- (void)setOTAProviderDelegate:(id<MTROTAProviderDelegate>)otaProviderDelegate queue:(dispatch_queue_t)queue;

@end

MTR_NEWLY_AVAILABLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,13 @@ - (void)setOperationalCertificateIssuer:(id<MTROperationalCertificateIssuer>)ope
_operationalCertificateIssuer = operationalCertificateIssuer;
_operationalCertificateIssuerQueue = queue;
}

- (void)setOTAProviderDelegate:(id<MTROTAProviderDelegate>)otaProviderDelegate queue:(dispatch_queue_t)queue
{
_otaProviderDelegate = otaProviderDelegate;
_otaProviderDelegateQueue = queue;
}

@end

@implementation MTRDeviceControllerExternalCertificateStartupParameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, readonly) dispatch_queue_t storageDelegateQueue;
@property (nonatomic, strong, readonly) NSUUID * uniqueIdentifier;

@property (nonatomic, strong, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
@property (nonatomic, strong, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;

@end

MTR_HIDDEN
Expand Down
16 changes: 13 additions & 3 deletions src/darwin/Framework/CHIP/MTRDeviceController_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
#import "MTRBaseDevice.h"
#import "MTRDeviceController.h"
#import "MTRDeviceControllerDataStore.h"
#import "MTRDeviceControllerStorageDelegate.h"

#import <Matter/MTRDeviceControllerStartupParams.h>
#import <Matter/MTRDeviceControllerStorageDelegate.h>
#import <Matter/MTROTAProviderDelegate.h>

@class MTRDeviceControllerStartupParamsInternal;
@class MTRDeviceControllerFactory;
Expand Down Expand Up @@ -75,12 +76,19 @@ NS_ASSUME_NONNULL_BEGIN
*
* This property MUST be gotten from the Matter work queue.
*/
@property (readonly, nullable) NSNumber * compressedFabricID;
@property (nonatomic, readonly, nullable) NSNumber * compressedFabricID;

/**
* The per-controller data store this controller was initialized with, if any.
*/
@property (nonatomic, nullable) MTRDeviceControllerDataStore * controllerDataStore;
@property (nonatomic, readonly, nullable) MTRDeviceControllerDataStore * controllerDataStore;

/**
* OTA delegate and its queue, if this controller supports OTA. Either both
* will be non-nil or both will be nil.
*/
@property (nonatomic, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
@property (nonatomic, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;

/**
* Init a newly created controller.
Expand All @@ -91,6 +99,8 @@ NS_ASSUME_NONNULL_BEGIN
queue:(dispatch_queue_t)queue
storageDelegate:(id<MTRDeviceControllerStorageDelegate> _Nullable)storageDelegate
storageDelegateQueue:(dispatch_queue_t _Nullable)storageDelegateQueue
otaProviderDelegate:(id<MTROTAProviderDelegate> _Nullable)otaProviderDelegate
otaProviderDelegateQueue:(dispatch_queue_t _Nullable)otaProviderDelegateQueue
uniqueIdentifier:(NSUUID *)uniqueIdentifier;

/**
Expand Down
5 changes: 1 addition & 4 deletions src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
class MTROTAProviderDelegateBridge : public chip::app::Clusters::OTAProviderDelegate
{
public:
MTROTAProviderDelegateBridge(id<MTROTAProviderDelegate> delegate);
MTROTAProviderDelegateBridge();
~MTROTAProviderDelegateBridge();

CHIP_ERROR Init(chip::System::Layer * systemLayer, chip::Messaging::ExchangeManager * exchangeManager);
Expand Down Expand Up @@ -65,9 +65,6 @@ class MTROTAProviderDelegateBridge : public chip::app::Clusters::OTAProviderDele
static void ConvertToNotifyUpdateAppliedParams(
const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::DecodableType & commandData,
MTROTASoftwareUpdateProviderClusterNotifyUpdateAppliedParams * commandParams);

_Nullable id<MTROTAProviderDelegate> mDelegate;
dispatch_queue_t mDelegateNotificationQueue;
};

NS_ASSUME_NONNULL_END
Loading