Skip to content

Commit

Permalink
Allow creating Darwin controllers via alloc/initWithParameters. (proj…
Browse files Browse the repository at this point in the history
…ect-chip#29025)

* Allow creating Darwin controllers via alloc/initWithParameters.

* Address review comment.
  • Loading branch information
bzbarsky-apple authored and abpoth committed Sep 12, 2023
1 parent 7f4d84c commit fb21091
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 197 deletions.
22 changes: 21 additions & 1 deletion src/darwin/Framework/CHIP/MTRDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@

@class MTRBaseDevice;

#if MTR_PER_CONTROLLER_STORAGE_ENABLED
@class MTRDeviceControllerParameters;
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

NS_ASSUME_NONNULL_BEGIN

MTR_DEPRECATED("Please use MTRBaseDevice deviceWithNodeID", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4))
Expand All @@ -37,11 +41,27 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS
@interface MTRDeviceController : NSObject

/**
* Controllers are created via the MTRDeviceControllerFactory object.
* Controllers are created via the MTRDeviceControllerFactory object or
* initialized via initWithParameters:error:.
*/
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

#if MTR_PER_CONTROLLER_STORAGE_ENABLED
/**
* Initialize a device controller with the provided parameters. This will:
*
* 1) Auto-start the MTRDeviceControllerFactory in storage-per-controller mode
* if it has not already been started.
* 2) Return nil or a running controller.
*
* Once this returns non-nil, it's the caller's resposibility to call shutdown
* on the controller to avoid leaking it.
*/
- (nullable instancetype)initWithParameters:(MTRDeviceControllerParameters *)parameters
error:(NSError * __autoreleasing *)error MTR_NEWLY_AVAILABLE;
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

/**
* If true, the controller has not been shut down yet.
*/
Expand Down
20 changes: 20 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
*/
#import <Matter/MTRDefines.h>

#if MTR_PER_CONTROLLER_STORAGE_ENABLED
#import <Matter/MTRDeviceControllerParameters.h>
#else
#import "MTRDeviceControllerParameters_Wrapper.h"
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

#import "MTRDeviceController_Internal.h"

#import "MTRAttestationTrustStoreBridge.h"
Expand Down Expand Up @@ -119,6 +125,20 @@ @interface MTRDeviceController () {

@implementation MTRDeviceController

- (nullable instancetype)initWithParameters:(MTRDeviceControllerParameters *)parameters error:(NSError * __autoreleasing *)error
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
if (!factory.isRunning) {
auto * params = [[MTRDeviceControllerFactoryParams alloc] initWithoutStorage];

if (![factory startControllerFactory:params error:error]) {
return nil;
}
}

return [factory initializeController:self withParameters:parameters error:error];
}

- (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
queue:(dispatch_queue_t)queue
storageDelegate:(id<MTRDeviceControllerStorageDelegate> _Nullable)storageDelegate
Expand Down
31 changes: 3 additions & 28 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@
#import <Foundation/Foundation.h>
#import <Matter/MTRCertificates.h>
#import <Matter/MTRDefines.h>
#if MTR_PER_CONTROLLER_STORAGE_ENABLED
#import <Matter/MTRDeviceControllerStartupParameters.h>
#else
@class MTRDeviceControllerStartupParameters;
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -42,6 +37,9 @@ NS_ASSUME_NONNULL_BEGIN

API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
@interface MTRDeviceControllerFactoryParams : NSObject

- (instancetype)init NS_UNAVAILABLE;

/*
* Storage used to store persistent information for the fabrics the
* controllers ends up interacting with. This is only used if "initWithStorage"
Expand Down Expand Up @@ -98,15 +96,6 @@ API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
*/
- (instancetype)initWithStorage:(id<MTRStorage>)storage;

#if MTR_PER_CONTROLLER_STORAGE_ENABLED
/*
* Initialize the device controller factory without storage. In this mode,
* device controllers will need to have per-controller storage provided to allow
* storing controller-specific information.
*/
- (instancetype)init MTR_NEWLY_AVAILABLE;
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

@end

API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
Expand Down Expand Up @@ -188,20 +177,6 @@ API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
- (MTRDeviceController * _Nullable)createControllerOnNewFabric:(MTRDeviceControllerStartupParams *)startupParams
error:(NSError * __autoreleasing *)error;

#if MTR_PER_CONTROLLER_STORAGE_ENABLED
/**
* Create an MTRDeviceController. Returns nil on failure.
*
* This method will fail if there is already a controller running for the given
* node identity.
*
* This method will fail if the controller factory was not initialized in
* storage-per-controller mode.
*/
- (MTRDeviceController * _Nullable)createController:(MTRDeviceControllerStartupParameters *)startupParameters
error:(NSError * __autoreleasing *)error MTR_NEWLY_AVAILABLE;
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

@end

MTR_DEPRECATED(
Expand Down
160 changes: 75 additions & 85 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
#import "MTRDeviceControllerFactory.h"
#import "MTRDeviceControllerFactory_Internal.h"

#import <Matter/MTRDefines.h>

#if MTR_PER_CONTROLLER_STORAGE_ENABLED
#import <Matter/MTRDeviceControllerParameters.h>
#else
#import "MTRDeviceControllerParameters_Wrapper.h"
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

#import "MTRCertificates.h"
#import "MTRControllerAccessControl.h"
#import "MTRDemuxingStorage.h"
Expand All @@ -34,9 +42,6 @@
#import "MTRPersistentStorageDelegateBridge.h"
#import "MTRSessionResumptionStorageBridge.h"
#import "NSDataSpanConversion.h"
#if !MTR_PER_CONTROLLER_STORAGE_ENABLED
#import "MTRDeviceControllerStartupParameters_Wrapper.h"
#endif // MTR_PER_CONTROLLER_STORAGE_ENABLED

#import <os/lock.h>

Expand Down Expand Up @@ -547,8 +552,12 @@ - (void)stopControllerFactory
* The fabricChecker block will run on the Matter queue, and is expected to
* return nil if pre-startup fabric table checks fail, and set fabricError to
* the right error value in that situation.
*
* The provided controller is expected to have just been allocated and to not be
* initialized yet.
*/
- (MTRDeviceController * _Nullable)_startDeviceController:(id)startupParams
- (MTRDeviceController * _Nullable)_startDeviceController:(MTRDeviceController *)controller
startupParams:(id)startupParams
fabricChecker:(MTRDeviceControllerStartupParamsInternal * (^)(FabricTable * fabricTable,
MTRDeviceController * controller,
CHIP_ERROR & fabricError))fabricChecker
Expand All @@ -566,8 +575,8 @@ - (MTRDeviceController * _Nullable)_startDeviceController:(id)startupParams
NSUUID * uniqueIdentifier;
id<MTROTAProviderDelegate> _Nullable otaProviderDelegate;
dispatch_queue_t _Nullable otaProviderDelegateQueue;
if ([startupParams isKindOfClass:[MTRDeviceControllerStartupParameters class]]) {
MTRDeviceControllerStartupParameters * params = startupParams;
if ([startupParams isKindOfClass:[MTRDeviceControllerParameters class]]) {
MTRDeviceControllerParameters * params = startupParams;
storageDelegate = params.storageDelegate;
storageDelegateQueue = params.storageDelegateQueue;
uniqueIdentifier = params.uniqueIdentifier;
Expand Down Expand Up @@ -608,20 +617,35 @@ - (MTRDeviceController * _Nullable)_startDeviceController:(id)startupParams
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];
controller = [controller initWithFactory:self
queue:_chipWorkQueue
storageDelegate:storageDelegate
storageDelegateQueue:storageDelegateQueue
otaProviderDelegate:otaProviderDelegate
otaProviderDelegateQueue:otaProviderDelegateQueue
uniqueIdentifier:uniqueIdentifier];
if (controller == nil) {
if (error != nil) {
*error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_NO_MEMORY];
*error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT];
}
return nil;
}

if ([_controllers count] == 0) {
// Bringing up the first controller. Start the event loop now. If we
// fail to bring it up, its cleanup will stop the event loop again.
chip::DeviceLayer::PlatformMgrImpl().StartEventLoopTask();
dispatch_sync(_chipWorkQueue, ^{
self->_operationalBrowser = new MTROperationalBrowser(self, self->_chipWorkQueue);
});
}

// Add the controller to _controllers now, so if we fail partway through its
// startup we will still do the right cleanups.
os_unfair_lock_lock(&_controllersLock);
[_controllers addObject:controller];
os_unfair_lock_unlock(&_controllersLock);

__block MTRDeviceControllerStartupParamsInternal * params = nil;
__block CHIP_ERROR fabricError = CHIP_NO_ERROR;

Expand Down Expand Up @@ -716,7 +740,8 @@ - (MTRDeviceController * _Nullable)createControllerOnExistingFabric:(MTRDeviceCo
return nil;
}

return [self _startDeviceController:startupParams
return [self _startDeviceController:[MTRDeviceController alloc]
startupParams:startupParams
fabricChecker:^MTRDeviceControllerStartupParamsInternal *(
FabricTable * fabricTable, MTRDeviceController * controller, CHIP_ERROR & fabricError) {
const FabricInfo * fabric = nullptr;
Expand Down Expand Up @@ -792,7 +817,8 @@ - (MTRDeviceController * _Nullable)createControllerOnNewFabric:(MTRDeviceControl
return nil;
}

return [self _startDeviceController:startupParams
return [self _startDeviceController:[MTRDeviceController alloc]
startupParams:startupParams
fabricChecker:^MTRDeviceControllerStartupParamsInternal *(
FabricTable * fabricTable, MTRDeviceController * controller, CHIP_ERROR & fabricError) {
const FabricInfo * fabric = nullptr;
Expand Down Expand Up @@ -825,73 +851,6 @@ - (MTRDeviceController * _Nullable)createControllerOnNewFabric:(MTRDeviceControl
error:error];
}

- (MTRDeviceController * _Nullable)createController:(MTRDeviceControllerStartupParameters *)startupParameters
error:(NSError * __autoreleasing *)error
{
[self _assertCurrentQueueIsNotMatterQueue];

return [self _startDeviceController:startupParameters
fabricChecker:^MTRDeviceControllerStartupParamsInternal *(
FabricTable * fabricTable, MTRDeviceController * controller, CHIP_ERROR & fabricError) {
auto advertiseOperational = self.advertiseOperational && startupParameters.shouldAdvertiseOperational;
auto * params =
[[MTRDeviceControllerStartupParamsInternal alloc] initForNewController:controller
fabricTable:fabricTable
keystore:self->_keystore
advertiseOperational:advertiseOperational
params:startupParameters
error:fabricError];
if (params != nil) {
if (params.productAttestationAuthorityCertificates == nil) {
params.productAttestationAuthorityCertificates = self.productAttestationAuthorityCertificates;
}
if (params.certificationDeclarationCertificates == nil) {
params.certificationDeclarationCertificates = self.certificationDeclarationCertificates;
}
}
return params;
}
error:error];
}

- (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];

MTRDeviceController * controller = [[MTRDeviceController alloc] initWithFactory:self
queue:_chipWorkQueue
storageDelegate:storageDelegate
storageDelegateQueue:storageDelegateQueue
otaProviderDelegate:otaProviderDelegate
otaProviderDelegateQueue:otaProviderDelegateQueue
uniqueIdentifier:uniqueIdentifier];
if (controller == nil) {
MTR_LOG_ERROR("Failed to init controller");
return nil;
}

if ([_controllers count] == 0) {
// Bringing up the first controller. Start the event loop now. If we
// fail to bring it up, its cleanup will stop the event loop again.
chip::DeviceLayer::PlatformMgrImpl().StartEventLoopTask();
dispatch_sync(_chipWorkQueue, ^{
self->_operationalBrowser = new MTROperationalBrowser(self, self->_chipWorkQueue);
});
}

// Add the controller to _controllers now, so if we fail partway through its
// startup we will still do the right cleanups.
os_unfair_lock_lock(&_controllersLock);
[_controllers addObject:controller];
os_unfair_lock_unlock(&_controllersLock);

return controller;
}

// Finds a fabric that matches the given params, if one exists.
//
// Returns NO on failure, YES on success. If YES is returned, the
Expand Down Expand Up @@ -1126,6 +1085,37 @@ - (void)operationalInstanceAdded:(chip::PeerId &)operationalID
}
}

- (MTRDeviceController * _Nullable)initializeController:(MTRDeviceController *)controller
withParameters:(MTRDeviceControllerParameters *)parameters
error:(NSError * __autoreleasing *)error
{
[self _assertCurrentQueueIsNotMatterQueue];

return [self _startDeviceController:controller
startupParams:parameters
fabricChecker:^MTRDeviceControllerStartupParamsInternal *(
FabricTable * fabricTable, MTRDeviceController * controller, CHIP_ERROR & fabricError) {
auto advertiseOperational = self.advertiseOperational && parameters.shouldAdvertiseOperational;
auto * params =
[[MTRDeviceControllerStartupParamsInternal alloc] initForNewController:controller
fabricTable:fabricTable
keystore:self->_keystore
advertiseOperational:advertiseOperational
params:parameters
error:fabricError];
if (params != nil) {
if (params.productAttestationAuthorityCertificates == nil) {
params.productAttestationAuthorityCertificates = self.productAttestationAuthorityCertificates;
}
if (params.certificationDeclarationCertificates == nil) {
params.certificationDeclarationCertificates = self.certificationDeclarationCertificates;
}
}
return params;
}
error:error];
}

- (PersistentStorageDelegate *)storageDelegate
{
return _persistentStorageDelegate;
Expand Down Expand Up @@ -1176,7 +1166,7 @@ - (instancetype)initWithStorage:(id<MTRStorage>)storage
return self;
}

- (instancetype)init
- (instancetype)initWithoutStorage
{
if (!(self = [super init])) {
return nil;
Expand All @@ -1191,7 +1181,7 @@ - (instancetype)init
_productAttestationAuthorityCertificates = nil;
_certificationDeclarationCertificates = nil;
_port = nil;
_shouldStartServer = NO;
_shouldStartServer = YES;

return self;
}
Expand Down
Loading

0 comments on commit fb21091

Please sign in to comment.