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 creating Darwin controllers via alloc/initWithParameters. #29025

Merged
merged 2 commits into from
Sep 6, 2023
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
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;
ksperling-apple marked this conversation as resolved.
Show resolved Hide resolved

return self;
}
Expand Down
Loading