From 2329976de0f488862702d315b84f71408908dbb2 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Wed, 4 Dec 2024 15:35:36 +0100 Subject: [PATCH] [darwin-framework-tool][XPC] Add a XPC server registry. --- examples/darwin-framework-tool/BUILD.gn | 1 + .../commands/common/CHIPCommandBridge.h | 6 ++ .../commands/common/CHIPCommandBridge.mm | 49 ++++++++-- .../commands/common/xpc/XPCServerRegistry.h | 56 +++++++++++ .../commands/common/xpc/XPCServerRegistry.mm | 98 +++++++++++++++++++ 5 files changed, 203 insertions(+), 7 deletions(-) create mode 100644 examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.h create mode 100644 examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.mm diff --git a/examples/darwin-framework-tool/BUILD.gn b/examples/darwin-framework-tool/BUILD.gn index 257431b2425aec..5f5dd397dfec2b 100644 --- a/examples/darwin-framework-tool/BUILD.gn +++ b/examples/darwin-framework-tool/BUILD.gn @@ -215,6 +215,7 @@ executable("darwin-framework-tool") { "commands/common/PreferencesStorage.mm", "commands/common/RemoteDataModelLogger.h", "commands/common/RemoteDataModelLogger.mm", + "commands/common/xpc/XPCServerRegistry.mm", "commands/configuration/Commands.h", "commands/configuration/ResetMRPParametersCommand.h", "commands/configuration/ResetMRPParametersCommand.mm", diff --git a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h index 7f9f3f9b6efc2c..bf6612ccf27537 100644 --- a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h +++ b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h @@ -52,6 +52,9 @@ class CHIPCommandBridge : public Command { AddArgument("commissioner-vendor-id", 0, UINT16_MAX, &mCommissionerVendorId, "The vendor id to use for darwin-framework-tool. If not provided, chip::VendorId::TestVendor1 (65521, 0xFFF1) will be " "used."); + AddArgument("use-xpc", 0, 1, &mUseXPC, "This option uses the XPC implementation."); + AddArgument("use-xpc-service-name", &mUseXPCServiceName, "The name of the XPC service to connect to."); + AddArgument("use-xpc-controller-id", &mUseXPCControllerId, "The id of the XPC controller to connect with."); } /////////// Command Interface ///////// @@ -168,4 +171,7 @@ class CHIPCommandBridge : public Command { chip::Optional mPaaTrustStorePath; chip::Optional mCommissionerVendorId; std::string mCurrentIdentity; + chip::Optional mUseXPC; + chip::Optional mUseXPCServiceName; + chip::Optional mUseXPCControllerId; }; diff --git a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm index 6b9dfcec29be9e..3f14abb50bb1a3 100644 --- a/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm +++ b/examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm @@ -31,6 +31,8 @@ #import "DeviceDelegate.h" #include "MTRError_Utils.h" +#include "xpc/XPCServerRegistry.h" + #include #include @@ -45,6 +47,17 @@ bool CHIPCommandBridge::sUseSharedStorage = true; constexpr char kTrustStorePathVariable[] = "PAA_TRUST_STORE_PATH"; +namespace { +NSString * ToNSString(const chip::Optional & string) +{ + if (!string.HasValue()) { + return nil; + } + + return @(string.Value()); +} +} + CHIP_ERROR CHIPCommandBridge::Run() { // In interactive mode, we want to avoid memory accumulating in the main autorelease pool, @@ -143,6 +156,8 @@ productAttestationAuthorityCertificates = nil; } + [[XPCServerRegistry sharedInstance] start]; + sUseSharedStorage = mCommissionerSharedStorage.ValueOr(false); if (sUseSharedStorage) { return SetUpStackWithSharedStorage(productAttestationAuthorityCertificates); @@ -202,7 +217,16 @@ params.productAttestationAuthorityCertificates = productAttestationAuthorityCertificates; - __auto_type * controller = [[MTRDeviceController alloc] initWithParameters:params error:&error]; + MTRDeviceController * controller = nil; + if (mUseXPC.ValueOr(false) || mUseXPCServiceName.HasValue()) { + __auto_type * identifier = uuidString; + if (commissionerName.compare(identities[i]) == 0 && mUseXPCControllerId.HasValue()) { + identifier = ToNSString(mUseXPCControllerId); + } + controller = [[XPCServerRegistry sharedInstance] createController:identifier serviceName:ToNSString(mUseXPCServiceName) params:params error:&error]; + } else { + controller = [[MTRDeviceController alloc] initWithParameters:params error:&error]; + } VerifyOrReturnError(nil != controller, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller startup failure: %@", error)); mControllers[identities[i]] = controller; } @@ -237,12 +261,21 @@ params.nodeId = @(mCommissionerNodeId.Value()); } - // We're not sure whether we're creating a new fabric or using an existing one, so just try both. - auto controller = [factory createControllerOnExistingFabric:params error:&error]; - if (controller == nil) { - // Maybe we didn't have this fabric yet. - params.vendorID = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1)); - controller = [factory createControllerOnNewFabric:params error:&error]; + MTRDeviceController * controller = nil; + if (mUseXPC.ValueOr(false) || mUseXPCServiceName.HasValue()) { + __auto_type * identifier = @(identities[i]); + if (commissionerName.compare(identities[i]) == 0 && mUseXPCControllerId.HasValue()) { + identifier = ToNSString(mUseXPCControllerId); + } + controller = [[XPCServerRegistry sharedInstance] createController:identifier serviceName:ToNSString(mUseXPCServiceName) params:params error:&error]; + } else { + // We're not sure whether we're creating a new fabric or using an existing one, so just try both. + controller = [factory createControllerOnExistingFabric:params error:&error]; + if (controller == nil) { + // Maybe we didn't have this fabric yet. + params.vendorID = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1)); + controller = [factory createControllerOnNewFabric:params error:&error]; + } } VerifyOrReturnError(nil != controller, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller startup failure: %@", error)); mControllers[identities[i]] = controller; @@ -256,6 +289,8 @@ if (IsInteractive()) { return; } + + [[XPCServerRegistry sharedInstance] stop]; ShutdownCommissioner(); } diff --git a/examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.h b/examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.h new file mode 100644 index 00000000000000..4000c7e50e760d --- /dev/null +++ b/examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol XPCServerBaseProtocol +- (void)start; +- (void)stop; +@end + +@protocol XPCServerExternalCertificateParametersProtocol +- (MTRDeviceController *)createController:(MTRDeviceControllerExternalCertificateParameters *)params error:(NSError * __autoreleasing *)error; +@end + +@protocol XPCServerStartupParametersProtocol +- (MTRDeviceController *)createController:(MTRDeviceControllerStartupParams *)params error:(NSError * __autoreleasing *)error; +@end + +@protocol XPCServerExternalCertificateParametersWithServiceNameProtocol +- (MTRDeviceController *)createController:(NSString *)controllerID serviceName:(NSString *)serviceName error:(NSError * __autoreleasing *)error; +@end + +@protocol XPCServerStartupParametersWithServiceNameProtocol +- (MTRDeviceController *)createController:(NSString *)controllerID serviceName:(NSString *)serviceName error:(NSError * __autoreleasing *)error; +@end + +@interface XPCServerRegistry : NSObject +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; ++ (XPCServerRegistry *)sharedInstance; + +- (void)register:(id)server; + +- (void)start; +- (void)stop; +- (MTRDeviceController *)createController:(NSString * _Nullable)controllerId serviceName:(NSString * _Nullable)serviceName params:(id)params error:(NSError * __autoreleasing *)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.mm b/examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.mm new file mode 100644 index 00000000000000..73b109044b0f09 --- /dev/null +++ b/examples/darwin-framework-tool/commands/common/xpc/XPCServerRegistry.mm @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "XPCServerRegistry.h" + +@interface XPCServerRegistry () +@property (strong, nonatomic) NSMutableArray> * servers; +@end + +@implementation XPCServerRegistry +- (instancetype)init +{ + if ((self = [super init])) { + _servers = [NSMutableArray new]; + } + + return self; +} + ++ (XPCServerRegistry *)sharedInstance +{ + static XPCServerRegistry * registry = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + registry = [[XPCServerRegistry alloc] init]; + }); + return registry; +} + +- (void)start +{ + for (id server in _servers) { + [server start]; + } +} + +- (void)stop +{ + for (id server in _servers) { + [server start]; + } +} + +- (void)register:(id)server +{ + [_servers addObject:server]; +} + +- (MTRDeviceController *)createController:(NSString * _Nullable)controllerId serviceName:(NSString * _Nullable)serviceName params:(id)params error:(NSError * __autoreleasing *)error +{ + return [self createControllerInternal:controllerId serviceName:serviceName params:params error:error]; +} + +- (MTRDeviceController *)createControllerInternal:(NSString * _Nullable)controllerId serviceName:(NSString * _Nullable)serviceName params:(id)params error:(NSError * __autoreleasing *)error +{ + BOOL isExternalCertificateParameters = [params isKindOfClass:[MTRDeviceControllerExternalCertificateParameters class]]; + BOOL isStartupParameters = [params isKindOfClass:[MTRDeviceControllerStartupParams class]]; + for (id server in _servers) { + if (controllerId && serviceName) { + if ([server conformsToProtocol:@protocol(XPCServerExternalCertificateParametersWithServiceNameProtocol)] && isExternalCertificateParameters) { + return [server createController:controllerId serviceName:serviceName error:error]; + } + + if ([server conformsToProtocol:@protocol(XPCServerStartupParametersWithServiceNameProtocol)] && isStartupParameters) { + return [server createController:controllerId serviceName:serviceName error:error]; + } + } else { + if ([server conformsToProtocol:@protocol(XPCServerExternalCertificateParametersProtocol)] && isExternalCertificateParameters) { + return [server createController:params error:error]; + } + + if ([server conformsToProtocol:@protocol(XPCServerStartupParametersProtocol)] && isStartupParameters) { + return [server createController:params error:error]; + } + } + } + + __auto_type * userInfo = @{ NSLocalizedDescriptionKey : @"No XPC servers support this configuration." }; + *error = [NSError errorWithDomain:@"Error" code:0 userInfo:userInfo]; + return nil; +} + +@end