Skip to content

Commit 015340a

Browse files
authored
[Matter.framework] Add back downloadLogOfType onto MTRBaseDevice and MTRDevice (project-chip#32373)
* [Matter.framework] Move downloadLogOfType from MTRDevice to MTRBaseDevice * [Matter.framework] Get downloadLogOfType to work over XPC * Add a simple test to MTRXPCProtocolTests.m to check that the XPC protocol works * Add a simple test to MTRXPCListenerSampleTests * [Matter.framework] Do not delete the file containing the log data once the downloadLogOfType completion is done * [Matter.framework] Get downloadLogOfType onto MTRDevice as well
1 parent d94a527 commit 015340a

11 files changed

+188
-8
lines changed

.github/workflows/darwin.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ jobs:
106106
working-directory: src/darwin/Framework
107107
run: |
108108
mkdir -p /tmp/darwin/framework-tests
109-
../../../out/debug/chip-all-clusters-app --interface-id -1 > >(tee /tmp/darwin/framework-tests/all-cluster-app.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-err.log >&2) &
109+
echo "This is a simple log" > /tmp/darwin/framework-tests/end_user_support_log.txt
110+
../../../out/debug/chip-all-clusters-app --interface-id -1 --end_user_support_log /tmp/darwin/framework-tests/end_user_support_log.txt > >(tee /tmp/darwin/framework-tests/all-cluster-app.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-err.log >&2) &
110111
../../../out/debug/chip-all-clusters-app --interface-id -1 --dac_provider ../../../credentials/development/commissioner_dut/struct_cd_origin_pid_vid_correct/test_case_vector.json --product-id 32768 --discriminator 3839 --secured-device-port 5539 --KVS /tmp/chip-all-clusters-app-kvs2 > >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid.log) 2> >(tee /tmp/darwin/framework-tests/all-cluster-app-origin-vid-err.log >&2) &
111112
112113
export TEST_RUNNER_ASAN_OPTIONS=__CURRENT_VALUE__:detect_stack_use_after_return=1

src/darwin/Framework/CHIP/MTRBaseDevice.h

+24
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#import <Matter/MTRCluster.h>
2121
#import <Matter/MTRDefines.h>
22+
#import <Matter/MTRDiagnosticLogsType.h>
2223

2324
@class MTRSetupPayload;
2425
@class MTRDeviceController;
@@ -542,6 +543,29 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1))
542543
reportHandler:(MTRDeviceResponseHandler)reportHandler
543544
subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished
544545
MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4));
546+
547+
/**
548+
* Download log of the desired type from the device.
549+
*
550+
* Note: The consumer of this API should move the file that the url points to or open it for reading before the
551+
* completion handler returns. Otherwise, the file will be deleted, and the data will be lost.
552+
*
553+
* @param type The type of log being requested. This should correspond to a value in the enum MTRDiagnosticLogType.
554+
* @param timeout The timeout for getting the log. If the timeout expires, completion will be called with whatever
555+
* has been retrieved by that point (which might be none or a partial log).
556+
* If the timeout is set to 0, the request will not expire and completion will not be called until
557+
* the log is fully retrieved or an error occurs.
558+
* @param queue The queue on which completion will be called.
559+
* @param completion The completion handler that is called after attempting to retrieve the requested log.
560+
* - In case of success, the completion handler is called with a non-nil URL and a nil error.
561+
* - If there is an error, a non-nil error is used and the url can be non-nil too if some logs have already been downloaded.
562+
*/
563+
- (void)downloadLogOfType:(MTRDiagnosticLogType)type
564+
timeout:(NSTimeInterval)timeout
565+
queue:(dispatch_queue_t)queue
566+
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
567+
MTR_NEWLY_AVAILABLE;
568+
545569
@end
546570

547571
/**

src/darwin/Framework/CHIP/MTRBaseDevice.mm

+13
Original file line numberDiff line numberDiff line change
@@ -2160,6 +2160,19 @@ + (NSDictionary *)eventReportForHeader:(const chip::app::EventHeader &)header an
21602160

21612161
return buffer;
21622162
}
2163+
2164+
- (void)downloadLogOfType:(MTRDiagnosticLogType)type
2165+
timeout:(NSTimeInterval)timeout
2166+
queue:(dispatch_queue_t)queue
2167+
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
2168+
{
2169+
[_deviceController downloadLogFromNodeWithID:@(_nodeID)
2170+
type:type
2171+
timeout:timeout
2172+
queue:queue
2173+
completion:completion];
2174+
}
2175+
21632176
@end
21642177

21652178
@implementation MTRBaseDevice (Deprecated)

src/darwin/Framework/CHIP/MTRDevice.h

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#import <Foundation/Foundation.h>
1919
#import <Matter/MTRBaseDevice.h>
2020
#import <Matter/MTRDefines.h>
21-
#import <Matter/MTRDiagnosticLogsType.h>
2221

2322
NS_ASSUME_NONNULL_BEGIN
2423

src/darwin/Framework/CHIP/MTRDevice.mm

+5-5
Original file line numberDiff line numberDiff line change
@@ -1760,11 +1760,11 @@ - (void)downloadLogOfType:(MTRDiagnosticLogType)type
17601760
queue:(dispatch_queue_t)queue
17611761
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
17621762
{
1763-
[_deviceController downloadLogFromNodeWithID:_nodeID
1764-
type:type
1765-
timeout:timeout
1766-
queue:queue
1767-
completion:completion];
1763+
auto * baseDevice = [self newBaseDevice];
1764+
[baseDevice downloadLogOfType:type
1765+
timeout:timeout
1766+
queue:queue
1767+
completion:completion];
17681768
}
17691769

17701770
#pragma mark - Cache management

src/darwin/Framework/CHIP/MTRDeviceController+XPC.h

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#import <Matter/MTRCluster.h>
2121
#import <Matter/MTRDefines.h>
2222
#import <Matter/MTRDeviceController.h>
23+
#import <Matter/MTRDiagnosticLogsType.h>
2324

2425
NS_ASSUME_NONNULL_BEGIN
2526

@@ -183,6 +184,15 @@ typedef void (^MTRValuesHandler)(id _Nullable values, NSError * _Nullable error)
183184
attributeId:(NSNumber * _Nullable)attributeId
184185
completion:(MTRValuesHandler)completion;
185186

187+
/**
188+
* Requests downloading some logs
189+
*/
190+
- (void)downloadLogWithController:(id _Nullable)controller
191+
nodeId:(NSNumber *)nodeId
192+
type:(MTRDiagnosticLogType)type
193+
timeout:(NSTimeInterval)timeout
194+
completion:(void (^)(NSString * _Nullable url, NSError * _Nullable error))completion MTR_NEWLY_AVAILABLE;
195+
186196
@end
187197

188198
/**

src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm

+4
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ + (NSXPCInterface *)xpcInterfaceForServerProtocol
220220
forSelector:@selector(readAttributeCacheWithController:nodeId:endpointId:clusterId:attributeId:completion:)
221221
argumentIndex:0
222222
ofReply:YES];
223+
[xpcInterface setClasses:GetXPCAllowedClasses()
224+
forSelector:@selector(downloadLogWithController:nodeId:type:timeout:completion:)
225+
argumentIndex:0
226+
ofReply:YES];
223227
return xpcInterface;
224228
}
225229

src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm

+32
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,38 @@ - (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator
427427
});
428428
}
429429

430+
- (void)downloadLogOfType:(MTRDiagnosticLogType)type
431+
timeout:(NSTimeInterval)timeout
432+
queue:(dispatch_queue_t)queue
433+
completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion
434+
{
435+
MTR_LOG_DEBUG("Downloading log ...");
436+
437+
__auto_type workBlock = ^(MTRDeviceControllerXPCProxyHandle * _Nullable handle, NSError * _Nullable error) {
438+
if (error != nil) {
439+
completion(nil, error);
440+
return;
441+
}
442+
443+
[handle.proxy downloadLogWithController:self.controllerID
444+
nodeId:self.nodeID
445+
type:type
446+
timeout:timeout
447+
completion:^(NSString * _Nullable url, NSError * _Nullable error) {
448+
dispatch_async(queue, ^{
449+
MTR_LOG_DEBUG("Download log");
450+
completion([NSURL URLWithString:url], error);
451+
// The following captures the proxy handle in the closure so that the
452+
// handle won't be released prior to block call.
453+
__auto_type handleRetainer = handle;
454+
(void) handleRetainer;
455+
});
456+
}];
457+
};
458+
459+
[self fetchProxyHandleWithQueue:queue completion:workBlock];
460+
}
461+
430462
- (void)fetchProxyHandleWithQueue:(dispatch_queue_t)queue completion:(MTRFetchProxyHandleCompletion)completion
431463
{
432464
if (self.controllerID != nil) {

src/darwin/Framework/CHIP/MTRDiagnosticLogsDownloader.mm

-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ - (instancetype)initWithType:(MTRDiagnosticLogType)type
165165
// data in the logs that the caller may find useful. For this reason, fileURL is passed in even
166166
// when there is an error but fileHandle is not nil.
167167
completion(strongSelf->_fileHandle ? fileURL : nil, bdxError);
168-
[strongSelf deleteFile];
169168

170169
done(strongSelf);
171170
}

src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m

+46
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,28 @@ - (void)getAnyDeviceControllerWithCompletion:(void (^)(id _Nullable controller,
167167
completion(MTRDeviceControllerId, nil);
168168
}
169169

170+
- (void)downloadLogWithController:(id)controller
171+
nodeId:(NSNumber *)nodeId
172+
type:(MTRDiagnosticLogType)type
173+
timeout:(NSTimeInterval)timeout
174+
completion:(void (^)(NSString * _Nullable url, NSError * _Nullable error))completion
175+
{
176+
(void) controller;
177+
__auto_type sharedController = sController;
178+
if (sharedController) {
179+
__auto_type device = [MTRBaseDevice deviceWithNodeID:nodeId controller:sharedController];
180+
[device downloadLogOfType:type
181+
timeout:timeout
182+
queue:dispatch_get_main_queue()
183+
completion:^(NSURL * _Nullable url, NSError * _Nullable error) {
184+
completion([url absoluteString], error);
185+
}];
186+
} else {
187+
NSLog(@"Failed to get shared controller");
188+
completion(nil, [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeGeneralError userInfo:nil]);
189+
}
190+
}
191+
170192
- (void)readAttributeWithController:(id)controller
171193
nodeId:(uint64_t)nodeId
172194
endpointId:(NSNumber * _Nullable)endpointId
@@ -1865,6 +1887,30 @@ - (void)test015_MTRDeviceInteraction
18651887
}, @(NO));
18661888
}
18671889

1890+
- (void)test016_DownloadLog
1891+
{
1892+
XCTestExpectation * expectation =
1893+
[self expectationWithDescription:@"Download EndUserSupport log"];
1894+
1895+
MTRBaseDevice * device = GetConnectedDevice();
1896+
dispatch_queue_t queue = dispatch_get_main_queue();
1897+
1898+
[device downloadLogOfType:MTRDiagnosticLogTypeEndUserSupport
1899+
timeout:10
1900+
queue:queue
1901+
completion:^(NSURL * _Nullable url, NSError * _Nullable error) {
1902+
NSLog(@"downloadLogOfType: url: %@, error: %@", url, error);
1903+
XCTAssertNil(error);
1904+
1905+
NSError * readError;
1906+
NSString * fileContent = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&readError];
1907+
XCTAssertNil(readError);
1908+
XCTAssertEqualObjects(fileContent, @"This is a simple log\n");
1909+
[expectation fulfill];
1910+
}];
1911+
[self waitForExpectationsWithTimeout:kTimeoutInSeconds handler:nil];
1912+
}
1913+
18681914
- (void)test900_SubscribeClusterStateCache
18691915
{
18701916
XCTestExpectation * expectation = [self expectationWithDescription:@"subscribe attributes by cache"];

src/darwin/Framework/CHIPTests/MTRXPCProtocolTests.m

+52
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ @interface MTRXPCProtocolTests<NSXPCListenerDelegate, CHIPRemoteDeviceProtocol>
116116
@property (readwrite, strong) void (^handleReadClusterStateCache)
117117
(id controller, NSNumber * nodeId, NSNumber * _Nullable endpointId, NSNumber * _Nullable clusterId,
118118
NSNumber * _Nullable attributeId, void (^completion)(id _Nullable values, NSError * _Nullable error));
119+
@property (readwrite, strong) void (^handleDownloadLog)(id controller, NSNumber * nodeId, MTRDiagnosticLogType type, NSTimeInterval timeout,
120+
void (^completion)(NSString * _Nullable url, NSError * _Nullable error));
119121

120122
@end
121123

@@ -274,6 +276,18 @@ - (void)readAttributeCacheWithController:(id _Nullable)controller
274276
});
275277
}
276278

279+
- (void)downloadLogWithController:(id)controller
280+
nodeId:(NSNumber *)nodeId
281+
type:(MTRDiagnosticLogType)type
282+
timeout:(NSTimeInterval)timeout
283+
completion:(void (^)(NSString * _Nullable url, NSError * _Nullable error))completion
284+
{
285+
dispatch_async(dispatch_get_main_queue(), ^{
286+
XCTAssertNotNil(self.handleDownloadLog);
287+
self.handleDownloadLog(controller, nodeId, type, timeout, completion);
288+
});
289+
}
290+
277291
- (void)setUp
278292
{
279293
[self setContinueAfterFailure:NO];
@@ -300,6 +314,44 @@ - (void)tearDown
300314
_xpcDisconnectExpectation = nil;
301315
}
302316

317+
- (void)testDownloadLogSuccess
318+
{
319+
uint64_t myNodeId = 9876543210;
320+
NSString * myBdxURL = @"bdx://foo";
321+
NSTimeInterval myTimeout = 10;
322+
323+
XCTestExpectation * callExpectation = [self expectationWithDescription:@"XPC call received"];
324+
XCTestExpectation * responseExpectation = [self expectationWithDescription:@"XPC response received"];
325+
326+
__auto_type uuid = self.controllerUUID;
327+
_handleDownloadLog = ^(id controller, NSNumber * nodeId, MTRDiagnosticLogType type, NSTimeInterval timeout,
328+
void (^completion)(NSString * _Nullable url, NSError * _Nullable error)) {
329+
XCTAssertTrue([controller isEqualToString:uuid]);
330+
XCTAssertEqual([nodeId unsignedLongLongValue], myNodeId);
331+
[callExpectation fulfill];
332+
completion(myBdxURL, nil);
333+
};
334+
335+
__auto_type * device = [MTRBaseDevice deviceWithNodeID:@(myNodeId) controller:_remoteDeviceController];
336+
NSLog(@"Device acquired. Downloading...");
337+
[device downloadLogOfType:MTRDiagnosticLogTypeEndUserSupport
338+
timeout:myTimeout
339+
queue:dispatch_get_main_queue()
340+
completion:^(NSURL * _Nullable url, NSError * _Nullable error) {
341+
NSLog(@"Read url: %@", url);
342+
XCTAssertNotNil(url);
343+
XCTAssertNil(error);
344+
[responseExpectation fulfill];
345+
self.xpcDisconnectExpectation = [self expectationWithDescription:@"XPC Disconnected"];
346+
}];
347+
348+
[self waitForExpectations:[NSArray arrayWithObjects:callExpectation, responseExpectation, nil] timeout:kTimeoutInSeconds];
349+
350+
// When download is done, connection should have been released
351+
[self waitForExpectations:[NSArray arrayWithObject:_xpcDisconnectExpectation] timeout:kTimeoutInSeconds];
352+
XCTAssertNil(_xpcConnection);
353+
}
354+
303355
- (void)testReadAttributeSuccess
304356
{
305357
uint64_t myNodeId = 9876543210;

0 commit comments

Comments
 (0)