Skip to content

Commit

Permalink
Allow specifying per-controller OTA delegates in Darwin.framework. (#…
Browse files Browse the repository at this point in the history
…29014)

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 authored and pull[bot] committed Nov 29, 2023
1 parent 8cf805a commit 8825684
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 95 deletions.
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 @@ -874,6 +853,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 @@ -882,6 +863,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 @@ -59,6 +60,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
7 changes: 7 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,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

0 comments on commit 8825684

Please sign in to comment.