Skip to content

Commit 1568486

Browse files
bzbarsky-applepull[bot]
authored andcommitted
Allow specifying per-controller OTA delegates in Darwin.framework. (#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.
1 parent 1ec26b5 commit 1568486

8 files changed

+155
-95
lines changed

src/darwin/Framework/CHIP/MTRDeviceController.mm

+54
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
123123
queue:(dispatch_queue_t)queue
124124
storageDelegate:(id<MTRDeviceControllerStorageDelegate> _Nullable)storageDelegate
125125
storageDelegateQueue:(dispatch_queue_t _Nullable)storageDelegateQueue
126+
otaProviderDelegate:(id<MTROTAProviderDelegate> _Nullable)otaProviderDelegate
127+
otaProviderDelegateQueue:(dispatch_queue_t _Nullable)otaProviderDelegateQueue
126128
uniqueIdentifier:(NSUUID *)uniqueIdentifier
127129
{
128130
if (self = [super init]) {
@@ -143,6 +145,58 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
143145
}
144146
}
145147

148+
// Ensure the otaProviderDelegate, if any, is valid.
149+
if (otaProviderDelegate == nil && otaProviderDelegateQueue != nil) {
150+
MTR_LOG_ERROR("Must have otaProviderDelegate when we have otaProviderDelegateQueue");
151+
return nil;
152+
}
153+
154+
if (otaProviderDelegate != nil && otaProviderDelegateQueue == nil) {
155+
MTR_LOG_ERROR("Must have otaProviderDelegateQueue when we have otaProviderDelegate");
156+
return nil;
157+
}
158+
159+
if (otaProviderDelegate != nil) {
160+
if (![otaProviderDelegate respondsToSelector:@selector(handleQueryImageForNodeID:controller:params:completion:)]
161+
&& ![otaProviderDelegate respondsToSelector:@selector(handleQueryImageForNodeID:
162+
controller:params:completionHandler:)]) {
163+
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleQueryImageForNodeID");
164+
return nil;
165+
}
166+
if (![otaProviderDelegate respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completion:)]
167+
&& ![otaProviderDelegate
168+
respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completionHandler:)]) {
169+
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleApplyUpdateRequestForNodeID");
170+
return nil;
171+
}
172+
if (![otaProviderDelegate respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:
173+
controller:params:completion:)]
174+
&& ![otaProviderDelegate
175+
respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:controller:params:completionHandler:)]) {
176+
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleNotifyUpdateAppliedForNodeID");
177+
return nil;
178+
}
179+
if (![otaProviderDelegate respondsToSelector:@selector
180+
(handleBDXTransferSessionBeginForNodeID:controller:fileDesignator:offset:completion:)]
181+
&& ![otaProviderDelegate respondsToSelector:@selector
182+
(handleBDXTransferSessionBeginForNodeID:
183+
controller:fileDesignator:offset:completionHandler:)]) {
184+
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXTransferSessionBeginForNodeID");
185+
return nil;
186+
}
187+
if (![otaProviderDelegate
188+
respondsToSelector:@selector(handleBDXQueryForNodeID:controller:blockSize:blockIndex:bytesToSkip:completion:)]
189+
&& ![otaProviderDelegate
190+
respondsToSelector:@selector(handleBDXQueryForNodeID:
191+
controller:blockSize:blockIndex:bytesToSkip:completionHandler:)]) {
192+
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXQueryForNodeID");
193+
return nil;
194+
}
195+
}
196+
197+
_otaProviderDelegate = otaProviderDelegate;
198+
_otaProviderDelegateQueue = otaProviderDelegateQueue;
199+
146200
_chipWorkQueue = queue;
147201
_factory = factory;
148202
_deviceMapLock = OS_UNFAIR_LOCK_INIT;

src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm

+43-60
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
static NSString * const kErrorControllerFactoryInit = @"Init failure while initializing controller factory";
6262
static NSString * const kErrorKeystoreInit = @"Init failure while initializing persistent storage keystore";
6363
static NSString * const kErrorCertStoreInit = @"Init failure while initializing persistent storage operational certificate store";
64-
static NSString * const kErrorOtaProviderInit = @"Init failure while creating an OTA provider delegate";
6564
static NSString * const kErrorSessionKeystoreInit = @"Init failure while initializing session keystore";
6665

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

125+
@property (nonatomic, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
126+
@property (nonatomic, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;
127+
126128
- (BOOL)findMatchingFabric:(FabricTable &)fabricTable
127129
params:(MTRDeviceControllerStartupParams *)params
128130
fabric:(const FabricInfo * _Nullable * _Nonnull)fabric;
@@ -289,9 +291,15 @@ - (void)cleanupInitObjects
289291

290292
- (void)cleanupStartupObjects
291293
{
292-
if (_otaProviderDelegateBridge) {
293-
delete _otaProviderDelegateBridge;
294-
_otaProviderDelegateBridge = nullptr;
294+
// Make sure the deinit order here is the reverse of the init order in
295+
// startControllerFactory:
296+
_certificationDeclarationCertificates = nil;
297+
_productAttestationAuthorityCertificates = nil;
298+
299+
if (_opCertStore) {
300+
_opCertStore->Finish();
301+
delete _opCertStore;
302+
_opCertStore = nullptr;
295303
}
296304

297305
if (_keystore) {
@@ -300,11 +308,12 @@ - (void)cleanupStartupObjects
300308
_keystore = nullptr;
301309
}
302310

303-
if (_opCertStore) {
304-
_opCertStore->Finish();
305-
delete _opCertStore;
306-
_opCertStore = nullptr;
311+
if (_otaProviderDelegateBridge) {
312+
delete _otaProviderDelegateBridge;
313+
_otaProviderDelegateBridge = nullptr;
307314
}
315+
_otaProviderDelegateQueue = nil;
316+
_otaProviderDelegate = nil;
308317

309318
if (_sessionResumptionStorage) {
310319
delete _sessionResumptionStorage;
@@ -412,57 +421,12 @@ - (BOOL)startControllerFactory:(MTRDeviceControllerFactoryParams *)startupParams
412421
return;
413422
}
414423

415-
if (startupParams.otaProviderDelegate) {
416-
if (![startupParams.otaProviderDelegate respondsToSelector:@selector(handleQueryImageForNodeID:
417-
controller:params:completion:)]
418-
&& ![startupParams.otaProviderDelegate
419-
respondsToSelector:@selector(handleQueryImageForNodeID:controller:params:completionHandler:)]) {
420-
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleQueryImageForNodeID");
421-
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
422-
return;
423-
}
424-
if (![startupParams.otaProviderDelegate
425-
respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completion:)]
426-
&& ![startupParams.otaProviderDelegate
427-
respondsToSelector:@selector(handleApplyUpdateRequestForNodeID:controller:params:completionHandler:)]) {
428-
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleApplyUpdateRequestForNodeID");
429-
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
430-
return;
431-
}
432-
if (![startupParams.otaProviderDelegate
433-
respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:controller:params:completion:)]
434-
&& ![startupParams.otaProviderDelegate
435-
respondsToSelector:@selector(handleNotifyUpdateAppliedForNodeID:controller:params:completionHandler:)]) {
436-
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleNotifyUpdateAppliedForNodeID");
437-
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
438-
return;
439-
}
440-
if (![startupParams.otaProviderDelegate
441-
respondsToSelector:@selector(handleBDXTransferSessionBeginForNodeID:
442-
controller:fileDesignator:offset:completion:)]
443-
&& ![startupParams.otaProviderDelegate
444-
respondsToSelector:@selector
445-
(handleBDXTransferSessionBeginForNodeID:controller:fileDesignator:offset:completionHandler:)]) {
446-
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXTransferSessionBeginForNodeID");
447-
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
448-
return;
449-
}
450-
if (![startupParams.otaProviderDelegate
451-
respondsToSelector:@selector(handleBDXQueryForNodeID:controller:blockSize:blockIndex:bytesToSkip:completion:)]
452-
&& ![startupParams.otaProviderDelegate
453-
respondsToSelector:@selector(handleBDXQueryForNodeID:
454-
controller:blockSize:blockIndex:bytesToSkip:completionHandler:)]) {
455-
MTR_LOG_ERROR("Error: MTROTAProviderDelegate does not support handleBDXQueryForNodeID");
456-
errorCode = CHIP_ERROR_INVALID_ARGUMENT;
457-
return;
458-
}
459-
_otaProviderDelegateBridge = new MTROTAProviderDelegateBridge(startupParams.otaProviderDelegate);
460-
if (_otaProviderDelegateBridge == nil) {
461-
MTR_LOG_ERROR("Error: %@", kErrorOtaProviderInit);
462-
errorCode = CHIP_ERROR_NO_MEMORY;
463-
return;
464-
}
424+
_otaProviderDelegate = startupParams.otaProviderDelegate;
425+
if (_otaProviderDelegate != nil) {
426+
_otaProviderDelegateQueue = dispatch_queue_create(
427+
"org.csa-iot.matter.framework.otaprovider.workqueue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
465428
}
429+
_otaProviderDelegateBridge = new MTROTAProviderDelegateBridge();
466430

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

597-
id<MTRDeviceControllerStorageDelegate> storageDelegate;
598-
dispatch_queue_t storageDelegateQueue;
561+
id<MTRDeviceControllerStorageDelegate> _Nullable storageDelegate;
562+
dispatch_queue_t _Nullable storageDelegateQueue;
599563
NSUUID * uniqueIdentifier;
564+
id<MTROTAProviderDelegate> _Nullable otaProviderDelegate;
565+
dispatch_queue_t _Nullable otaProviderDelegateQueue;
600566
if ([startupParams isKindOfClass:[MTRDeviceControllerStartupParameters class]]) {
601567
MTRDeviceControllerStartupParameters * params = startupParams;
602568
storageDelegate = params.storageDelegate;
603569
storageDelegateQueue = params.storageDelegateQueue;
604570
uniqueIdentifier = params.uniqueIdentifier;
571+
otaProviderDelegate = params.otaProviderDelegate;
572+
otaProviderDelegateQueue = params.otaProviderDelegateQueue;
605573
} else if ([startupParams isKindOfClass:[MTRDeviceControllerStartupParams class]]) {
606574
MTRDeviceControllerStartupParams * params = startupParams;
607575
storageDelegate = nil;
608576
storageDelegateQueue = nil;
609577
uniqueIdentifier = params.uniqueIdentifier;
578+
otaProviderDelegate = nil;
579+
otaProviderDelegateQueue = nil;
610580
} else {
611581
MTR_LOG_ERROR("Unknown kind of startup params: %@", startupParams);
612582
return nil;
@@ -628,10 +598,19 @@ - (MTRDeviceController * _Nullable)_startDeviceController:(id)startupParams
628598
return nil;
629599
}
630600

601+
// Fall back to the factory-wide OTA provider delegate if one is not
602+
// provided in the startup params.
603+
if (otaProviderDelegate == nil) {
604+
otaProviderDelegate = self.otaProviderDelegate;
605+
otaProviderDelegateQueue = self.otaProviderDelegateQueue;
606+
}
607+
631608
// Create the controller, so we start the event loop, since we plan to do
632609
// our fabric table operations there.
633610
auto * controller = [self _createController:storageDelegate
634611
storageDelegateQueue:storageDelegateQueue
612+
otaProviderDelegate:otaProviderDelegate
613+
otaProviderDelegateQueue:otaProviderDelegateQueue
635614
uniqueIdentifier:uniqueIdentifier];
636615
if (controller == nil) {
637616
if (error != nil) {
@@ -874,6 +853,8 @@ - (MTRDeviceController * _Nullable)createController:(MTRDeviceControllerStartupP
874853

875854
- (MTRDeviceController * _Nullable)_createController:(id<MTRDeviceControllerStorageDelegate> _Nullable)storageDelegate
876855
storageDelegateQueue:(dispatch_queue_t _Nullable)storageDelegateQueue
856+
otaProviderDelegate:(id<MTROTAProviderDelegate> _Nullable)otaProviderDelegate
857+
otaProviderDelegateQueue:(dispatch_queue_t _Nullable)otaProviderDelegateQueue
877858
uniqueIdentifier:(NSUUID *)uniqueIdentifier
878859
{
879860
[self _assertCurrentQueueIsNotMatterQueue];
@@ -882,6 +863,8 @@ - (MTRDeviceController * _Nullable)_createController:(id<MTRDeviceControllerStor
882863
queue:_chipWorkQueue
883864
storageDelegate:storageDelegate
884865
storageDelegateQueue:storageDelegateQueue
866+
otaProviderDelegate:otaProviderDelegate
867+
otaProviderDelegateQueue:otaProviderDelegateQueue
885868
uniqueIdentifier:uniqueIdentifier];
886869
if (controller == nil) {
887870
MTR_LOG_ERROR("Failed to init controller");

src/darwin/Framework/CHIP/MTRDeviceControllerStartupParameters.h

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#import <Matter/MTRDefines.h>
2020
#import <Matter/MTRDeviceControllerStorageDelegate.h>
21+
#import <Matter/MTROTAProviderDelegate.h>
2122

2223
NS_ASSUME_NONNULL_BEGIN
2324

@@ -59,6 +60,12 @@ MTR_NEWLY_AVAILABLE
5960
- (void)setOperationalCertificateIssuer:(id<MTROperationalCertificateIssuer>)operationalCertificateIssuer
6061
queue:(dispatch_queue_t)queue;
6162

63+
/**
64+
* Set an MTROTAProviderDelegate to call (on the provided queue). Only needs to
65+
* be called if this controller should be able to handle OTA for devices.
66+
*/
67+
- (void)setOTAProviderDelegate:(id<MTROTAProviderDelegate>)otaProviderDelegate queue:(dispatch_queue_t)queue;
68+
6269
@end
6370

6471
MTR_NEWLY_AVAILABLE

src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm

+7
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,13 @@ - (void)setOperationalCertificateIssuer:(id<MTROperationalCertificateIssuer>)ope
288288
_operationalCertificateIssuer = operationalCertificateIssuer;
289289
_operationalCertificateIssuerQueue = queue;
290290
}
291+
292+
- (void)setOTAProviderDelegate:(id<MTROTAProviderDelegate>)otaProviderDelegate queue:(dispatch_queue_t)queue
293+
{
294+
_otaProviderDelegate = otaProviderDelegate;
295+
_otaProviderDelegateQueue = queue;
296+
}
297+
291298
@end
292299

293300
@implementation MTRDeviceControllerExternalCertificateStartupParameters

src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams_Internal.h

+3
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ NS_ASSUME_NONNULL_BEGIN
7777
@property (nonatomic, strong, readonly) dispatch_queue_t storageDelegateQueue;
7878
@property (nonatomic, strong, readonly) NSUUID * uniqueIdentifier;
7979

80+
@property (nonatomic, strong, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
81+
@property (nonatomic, strong, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;
82+
8083
@end
8184

8285
MTR_HIDDEN

src/darwin/Framework/CHIP/MTRDeviceController_Internal.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
#import "MTRBaseDevice.h"
3131
#import "MTRDeviceController.h"
3232
#import "MTRDeviceControllerDataStore.h"
33-
#import "MTRDeviceControllerStorageDelegate.h"
3433

3534
#import <Matter/MTRDeviceControllerStartupParams.h>
35+
#import <Matter/MTRDeviceControllerStorageDelegate.h>
36+
#import <Matter/MTROTAProviderDelegate.h>
3637

3738
@class MTRDeviceControllerStartupParamsInternal;
3839
@class MTRDeviceControllerFactory;
@@ -75,12 +76,19 @@ NS_ASSUME_NONNULL_BEGIN
7576
*
7677
* This property MUST be gotten from the Matter work queue.
7778
*/
78-
@property (readonly, nullable) NSNumber * compressedFabricID;
79+
@property (nonatomic, readonly, nullable) NSNumber * compressedFabricID;
7980

8081
/**
8182
* The per-controller data store this controller was initialized with, if any.
8283
*/
83-
@property (nonatomic, nullable) MTRDeviceControllerDataStore * controllerDataStore;
84+
@property (nonatomic, readonly, nullable) MTRDeviceControllerDataStore * controllerDataStore;
85+
86+
/**
87+
* OTA delegate and its queue, if this controller supports OTA. Either both
88+
* will be non-nil or both will be nil.
89+
*/
90+
@property (nonatomic, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
91+
@property (nonatomic, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;
8492

8593
/**
8694
* Init a newly created controller.
@@ -91,6 +99,8 @@ NS_ASSUME_NONNULL_BEGIN
9199
queue:(dispatch_queue_t)queue
92100
storageDelegate:(id<MTRDeviceControllerStorageDelegate> _Nullable)storageDelegate
93101
storageDelegateQueue:(dispatch_queue_t _Nullable)storageDelegateQueue
102+
otaProviderDelegate:(id<MTROTAProviderDelegate> _Nullable)otaProviderDelegate
103+
otaProviderDelegateQueue:(dispatch_queue_t _Nullable)otaProviderDelegateQueue
94104
uniqueIdentifier:(NSUUID *)uniqueIdentifier;
95105

96106
/**

src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
2424
class MTROTAProviderDelegateBridge : public chip::app::Clusters::OTAProviderDelegate
2525
{
2626
public:
27-
MTROTAProviderDelegateBridge(id<MTROTAProviderDelegate> delegate);
27+
MTROTAProviderDelegateBridge();
2828
~MTROTAProviderDelegateBridge();
2929

3030
CHIP_ERROR Init(chip::System::Layer * systemLayer, chip::Messaging::ExchangeManager * exchangeManager);
@@ -65,9 +65,6 @@ class MTROTAProviderDelegateBridge : public chip::app::Clusters::OTAProviderDele
6565
static void ConvertToNotifyUpdateAppliedParams(
6666
const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::DecodableType & commandData,
6767
MTROTASoftwareUpdateProviderClusterNotifyUpdateAppliedParams * commandParams);
68-
69-
_Nullable id<MTROTAProviderDelegate> mDelegate;
70-
dispatch_queue_t mDelegateNotificationQueue;
7168
};
7269

7370
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)