Skip to content

Commit

Permalink
[darwin] Add support for downloading diagnostic logs (#31638)
Browse files Browse the repository at this point in the history
* [Matter.framework] Add MTRDiagnosticLogsDelegate to the Matter.framework

* [darwin-framework-tool] Add bdx commands to darwin-framework-tool
  • Loading branch information
vivien-apple authored Jan 24, 2024
1 parent f44eb6b commit 57898b9
Show file tree
Hide file tree
Showing 16 changed files with 971 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/darwin-framework-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ executable("darwin-framework-tool") {
"${chip_root}/examples/chip-tool/commands/common/Commands.h",
"${chip_root}/examples/chip-tool/commands/common/HexConversion.h",
"${chip_root}/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp",
"commands/bdx/Commands.h",
"commands/bdx/DownloadLogCommand.mm",
"commands/clusters/ClusterCommandBridge.h",
"commands/clusters/ModelCommandBridge.mm",
"commands/clusters/ReportCommandBridge.h",
Expand Down
32 changes: 32 additions & 0 deletions examples/darwin-framework-tool/commands/bdx/Commands.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 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.
*
*/

#pragma once

#include "commands/bdx/DownloadLogCommand.h"
#include "commands/common/Commands.h"

void registerCommandsBdx(Commands & commands)
{
const char * clusterName = "Bdx";
commands_list clusterCommands = {
make_unique<DownloadLogCommand>(), //
};

commands.RegisterCommandSet(clusterName, clusterCommands, "Commands related to BDX");
}
45 changes: 45 additions & 0 deletions examples/darwin-framework-tool/commands/bdx/DownloadLogCommand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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.
*
*/

#pragma once

#include "../common/CHIPCommandBridge.h"

class DownloadLogCommand : public CHIPCommandBridge
{
public:
DownloadLogCommand() : CHIPCommandBridge("download")
{
AddArgument("node-id", 0, UINT64_MAX, &mNodeId, "Node to download the logs from.");
AddArgument("log-type", 0, 2, &mLogType,
"The type of log being requested. This should correspond to a value in the enum MTRDiagnosticLogType.");
AddArgument("timeout", 0, UINT16_MAX, &mTimeout,
"The timeout for getting the log. If the timeout expires, completion will be called with whatever has been "
"retrieved by that point (which might be none or a partial log). If the timeout is set to 0, the request will "
"not expire and completion will not be called until the log is fully retrieved or an error occurs.");
}

/////////// CHIPCommandBridge Interface /////////
CHIP_ERROR RunCommand() override;
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); }

private:
chip::NodeId mNodeId;
uint8_t mLogType;
uint16_t mTimeout;
};
58 changes: 58 additions & 0 deletions examples/darwin-framework-tool/commands/bdx/DownloadLogCommand.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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 <Matter/Matter.h>

#import "MTRError_Utils.h"

#include "DownloadLogCommand.h"

CHIP_ERROR DownloadLogCommand::RunCommand()
{
ChipLogProgress(chipTool, "Downloading logs from node 0x" ChipLogFormatX64, ChipLogValueX64(mNodeId));

MTRDeviceController * commissioner = CurrentCommissioner();
auto * device = [MTRDevice deviceWithNodeID:@(mNodeId) controller:commissioner];

auto logType = static_cast<MTRDiagnosticLogType>(mLogType);
auto queue = dispatch_queue_create("com.chip.bdx.downloader", DISPATCH_QUEUE_SERIAL);

auto * self = this;
auto completion = ^(NSURL * url, NSError * error) {
// A non-nil url indicates the presence of content, which can occur even in error scenarios like timeouts.
if (nil != url) {
NSError * readError = nil;
auto * data = [NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&readError];
VerifyOrReturn(nil == readError, self->SetCommandExitStatus(MTRErrorToCHIPErrorCode(readError)));

auto * content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Content: %@", content);
}

VerifyOrReturn(nil == error, self->SetCommandExitStatus(MTRErrorToCHIPErrorCode(error)));

// The url is nil when there are no logs on the target device.
if (nil == url) {
NSLog(@"No logs has been found onto node 0x" ChipLogFormatX64, ChipLogValueX64(mNodeId));
}
self->SetCommandExitStatus(CHIP_NO_ERROR);
};

[device downloadLogOfType:logType timeout:mTimeout queue:queue completion:completion];
return CHIP_NO_ERROR;
}
2 changes: 2 additions & 0 deletions examples/darwin-framework-tool/main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#import "logging/logging.h"

#include "commands/bdx/Commands.h"
#include "commands/common/Commands.h"
#include "commands/delay/Commands.h"
#include "commands/discover/Commands.h"
Expand All @@ -38,6 +39,7 @@ int main(int argc, const char * argv[])
dft::logging::Setup();

Commands commands;
registerCommandsBdx(commands);
registerCommandsPairing(commands);
registerCommandsDelay(commands);
registerCommandsDiscover(commands);
Expand Down
21 changes: 21 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#import <Foundation/Foundation.h>
#import <Matter/MTRBaseDevice.h>
#import <Matter/MTRDefines.h>
#import <Matter/MTRDiagnosticLogsType.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -325,6 +326,26 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1))
*/
- (void)removeClientDataForKey:(NSString *)key endpointID:(NSNumber *)endpointID MTR_UNSTABLE_API;

/**
* Download log of the desired type from the device.
*
* Note: The consumer of this API should move the file that the url points to or open it for reading before the
* completion handler returns. Otherwise, the file will be deleted, and the data will be lost.
*
* @param type The type of log being requested. This should correspond to a value in the enum MTRDiagnosticLogType.
* @param timeout The timeout for getting the log. If the timeout expires, completion will be called with whatever
* has been retrieved by that point (which might be none or a partial log).
* If the timeout is set to 0, the request will not expire and completion will not be called until
* the log is fully retrieved or an error occurs.
* @param queue The queue on which completion will be called.
* @param completion The completion that will be called to return the URL of the requested log if successful. Otherwise
* returns an error.
*/
- (void)downloadLogOfType:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
MTR_NEWLY_AVAILABLE;
@end

@protocol MTRDeviceDelegate <NSObject>
Expand Down
12 changes: 12 additions & 0 deletions src/darwin/Framework/CHIP/MTRDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,18 @@ - (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator
[baseDevice openCommissioningWindowWithDiscriminator:discriminator duration:duration queue:queue completion:completion];
}

- (void)downloadLogOfType:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
{
[_deviceController downloadLogFromNodeWithID:_nodeID
type:type
timeout:timeout
queue:queue
completion:completion];
}

#pragma mark - Cache management

// assume lock is held
Expand Down
14 changes: 14 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,20 @@ - (void)operationalInstanceAdded:(chip::NodeId)nodeID
[device nodeMayBeAdvertisingOperational];
}

- (void)downloadLogFromNodeWithID:(NSNumber *)nodeID
type:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
{
[_factory downloadLogFromNodeWithID:nodeID
controller:self
type:type
timeout:timeout
queue:queue
completion:completion];
}

@end

/**
Expand Down
32 changes: 32 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#import "MTRDeviceControllerStartupParams.h"
#import "MTRDeviceControllerStartupParams_Internal.h"
#import "MTRDeviceController_Internal.h"
#import "MTRDiagnosticLogsDownloader.h"
#import "MTRError_Internal.h"
#import "MTRFabricInfo_Internal.h"
#import "MTRFramework.h"
Expand Down Expand Up @@ -133,6 +134,8 @@ @interface MTRDeviceControllerFactory ()
@property (nonatomic, readonly, nullable) id<MTROTAProviderDelegate> otaProviderDelegate;
@property (nonatomic, readonly, nullable) dispatch_queue_t otaProviderDelegateQueue;

@property (nonatomic, readonly) MTRDiagnosticLogsDownloader * diagnosticLogsDownloader;

- (BOOL)findMatchingFabric:(FabricTable &)fabricTable
params:(MTRDeviceControllerStartupParams *)params
fabric:(const FabricInfo * _Nullable * _Nonnull)fabric;
Expand Down Expand Up @@ -332,6 +335,8 @@ - (void)cleanupStartupObjects
delete _persistentStorageDelegate;
_persistentStorageDelegate = nullptr;
}

_diagnosticLogsDownloader = nil;
}

- (CHIP_ERROR)_initFabricTable:(FabricTable &)fabricTable
Expand Down Expand Up @@ -1066,6 +1071,33 @@ - (nullable MTRDeviceController *)runningControllerForFabricIndex:(chip::FabricI
return [self runningControllerForFabricIndex:fabricIndex includeControllerStartingUp:YES includeControllerShuttingDown:YES];
}

- (void)downloadLogFromNodeWithID:(NSNumber *)nodeID
controller:(MTRDeviceController *)controller
type:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
{
dispatch_sync(_chipWorkQueue, ^{
if (![self isRunning]) {
return;
}

if (_diagnosticLogsDownloader == nil) {
_diagnosticLogsDownloader = [[MTRDiagnosticLogsDownloader alloc] init];
auto systemState = _controllerFactory->GetSystemState();
systemState->BDXTransferServer()->SetDelegate([_diagnosticLogsDownloader getBridge]);
}

[_diagnosticLogsDownloader downloadLogFromNodeWithID:nodeID
controller:controller
type:type
timeout:timeout
queue:queue
completion:completion];
});
}

- (void)operationalInstanceAdded:(chip::PeerId &)operationalID
{
assertChipStackLockedByCurrentThread();
Expand Down
11 changes: 11 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import <Foundation/Foundation.h>
#import <Matter/MTRDefines.h>
#import <Matter/MTRDeviceController.h>
#import <Matter/MTRDiagnosticLogsType.h>

#if MTR_PER_CONTROLLER_STORAGE_ENABLED
#import <Matter/MTRDeviceControllerParameters.h>
Expand Down Expand Up @@ -75,6 +76,16 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)operationalInstanceAdded:(chip::PeerId &)operationalID;

/**
* Download log of the desired type from the device.
*/
- (void)downloadLogFromNodeWithID:(NSNumber *)nodeID
controller:(MTRDeviceController *)controller
type:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion;

/**
* Initialize an MTRDeviceController with the given parameters.
*/
Expand Down
10 changes: 10 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#import <Matter/MTRDefines.h>
#import <Matter/MTRDeviceControllerStartupParams.h>
#import <Matter/MTRDiagnosticLogsType.h>
#if MTR_PER_CONTROLLER_STORAGE_ENABLED
#import <Matter/MTRDeviceControllerStorageDelegate.h>
#else
Expand Down Expand Up @@ -233,6 +234,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)operationalInstanceAdded:(chip::NodeId)nodeID;

/**
* Download log of the desired type from the device.
*/
- (void)downloadLogFromNodeWithID:(NSNumber *)nodeID
type:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion;

#pragma mark - Device-specific data and SDK access
// DeviceController will act as a central repository for this opaque dictionary that MTRDevice manages
- (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID;
Expand Down
42 changes: 42 additions & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticLogsDownloader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
*
* Copyright (c) 2024 Project CHIP Authors
*
* 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 <Foundation/Foundation.h>

#import <Matter/MTRDeviceController.h>
#import <Matter/MTRDiagnosticLogsType.h>

namespace chip {
namespace bdx {
class BDXTransferServerDelegate;
}
}

NS_ASSUME_NONNULL_BEGIN

@interface MTRDiagnosticLogsDownloader : NSObject
- (chip::bdx::BDXTransferServerDelegate *)getBridge;

- (void)downloadLogFromNodeWithID:(NSNumber *)nodeID
controller:(MTRDeviceController *)controller
type:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion;
@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 57898b9

Please sign in to comment.