Skip to content

Commit 41be641

Browse files
Disallow read-through on internally-created MTRDevice instances. (#35302)
We want to be able to instantiate an MTRDevice and readAttibute to get its cached state without ever triggering read-throughs. The MTRDiagnosticLogsDownloader.mm changes were because it was using internal APIs to create an MTRDevice when it does not need an MTRDevice at all.
1 parent 1a892ed commit 41be641

File tree

5 files changed

+44
-17
lines changed

5 files changed

+44
-17
lines changed

src/darwin/Framework/CHIP/MTRDevice.h

+4-6
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,11 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1))
3737
+ (instancetype)new NS_UNAVAILABLE;
3838

3939
/**
40-
* TODO: Document usage better
40+
* Get an MTRDevice object representing a device with a specific node ID
41+
* associated with a specific controller.
4142
*
42-
* Directly instantiate a MTRDevice with a MTRDeviceController as a shim.
43-
*
44-
* All device-specific information would be stored on the device controller, and
45-
* retrieved when performing actions using a combination of MTRBaseDevice
46-
* and MTRAsyncCallbackQueue.
43+
* MTRDevice objects are stateful, and callers should hold on to the MTRDevice
44+
* while they are using it.
4745
*/
4846
+ (MTRDevice *)deviceWithNodeID:(NSNumber *)nodeID
4947
controller:(MTRDeviceController *)controller MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4));

src/darwin/Framework/CHIP/MTRDevice.mm

+13-1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ - (instancetype)initForSubclassesWithNodeID:(NSNumber *)nodeID controller:(MTRDe
306306
_delegates = [NSMutableSet set];
307307
_deviceController = controller;
308308
_nodeID = nodeID;
309+
_accessedViaPublicAPI = NO;
309310
_state = MTRDeviceStateUnknown;
310311
}
311312

@@ -321,6 +322,7 @@ - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceControlle
321322
_nodeID = [nodeID copy];
322323
_fabricIndex = controller.fabricIndex;
323324
_deviceController = controller;
325+
_accessedViaPublicAPI = NO;
324326
_queue
325327
= dispatch_queue_create("org.csa-iot.matter.framework.device.workqueue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
326328
_asyncWorkQueue = [[MTRAsyncWorkQueue alloc] initWithContext:self];
@@ -360,11 +362,21 @@ - (void)dealloc
360362
MTR_LOG("MTRDevice dealloc: %p", self);
361363
}
362364

363-
+ (MTRDevice *)deviceWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller
365+
+ (MTRDevice *)_deviceWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller
364366
{
365367
return [controller deviceForNodeID:nodeID];
366368
}
367369

370+
+ (MTRDevice *)deviceWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller
371+
{
372+
auto * device = [self _deviceWithNodeID:nodeID controller:controller];
373+
if (device) {
374+
std::lock_guard lock(device->_lock);
375+
device->_accessedViaPublicAPI = YES;
376+
}
377+
return device;
378+
}
379+
368380
#pragma mark - Time Synchronization
369381

370382
- (void)_setTimeOnDevice

src/darwin/Framework/CHIP/MTRDevice_Concrete.mm

+9-6
Original file line numberDiff line numberDiff line change
@@ -464,11 +464,6 @@ - (NSString *)description
464464
stringWithFormat:@"<MTRDevice: %p, XPC: NO, node: %016llX-%016llX (%llu), VID: %@, PID: %@, WiFi: %@, Thread: %@, state: %@, last subscription attempt wait: %lus, queued work: %lu, last report: %@%@, last subscription failure: %@%@, controller: %@>", self, _deviceController.compressedFabricID.unsignedLongLongValue, _nodeID.unsignedLongLongValue, _nodeID.unsignedLongLongValue, vid, pid, wifi, thread, InternalDeviceStateString(internalDeviceState), static_cast<unsigned long>(lastSubscriptionAttemptWait), static_cast<unsigned long>(_asyncWorkQueue.itemCount), mostRecentReportTime, reportAge, lastSubscriptionFailureTime, subscriptionFailureAge, _deviceController.uniqueIdentifier];
465465
}
466466

467-
+ (MTRDevice *)deviceWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller
468-
{
469-
return [controller deviceForNodeID:nodeID];
470-
}
471-
472467
#pragma mark - Time Synchronization
473468

474469
- (void)_setTimeOnDevice
@@ -2593,7 +2588,15 @@ static BOOL AttributeHasChangesOmittedQuality(MTRAttributePath * attributePath)
25932588
// 2. The attribute has the Changes Omitted quality, so we won't get reports for it.
25942589
// 3. The attribute is not in the spec, and the read params asks to assume
25952590
// an unknown attribute has the Changes Omitted quality.
2596-
if (![self _subscriptionAbleToReport] || hasChangesOmittedQuality) {
2591+
//
2592+
// But all this only happens if this device has been accessed via the public
2593+
// API. If it's a device we just created internally, don't do read-throughs.
2594+
BOOL readThroughsAllowed;
2595+
{
2596+
std::lock_guard lock(_lock);
2597+
readThroughsAllowed = _accessedViaPublicAPI;
2598+
}
2599+
if (readThroughsAllowed && (![self _subscriptionAbleToReport] || hasChangesOmittedQuality)) {
25972600
// Read requests container will be a mutable array of items, each being an array containing:
25982601
// [attribute request path, params]
25992602
// Batching handler should only coalesce when params are equal.

src/darwin/Framework/CHIP/MTRDevice_Internal.h

+11
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,19 @@ MTR_DIRECT_MEMBERS
120120
// Our controller. Declared nullable because our property is, though in
121121
// practice it does not look like we ever set it to nil.
122122
MTRDeviceController * _Nullable _deviceController;
123+
124+
// Whether this device has been accessed via the public deviceWithNodeID API
125+
// (as opposed to just via the internal _deviceWithNodeID).
126+
BOOL _accessedViaPublicAPI;
123127
}
124128

129+
/**
130+
* Internal way of creating an MTRDevice that does not flag the device as being
131+
* visible to external API consumers.
132+
*/
133+
+ (MTRDevice *)_deviceWithNodeID:(NSNumber *)nodeID
134+
controller:(MTRDeviceController *)controller;
135+
125136
- (instancetype)initForSubclassesWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller;
126137
- (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller;
127138

src/darwin/Framework/CHIP/MTRDiagnosticLogsDownloader.mm

+7-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616
*/
1717

1818
#import "MTRDiagnosticLogsDownloader.h"
19+
#import <Matter/Matter.h>
1920

21+
#include <platform/CHIPDeviceLayer.h>
22+
#include <platform/LockTracker.h>
2023
#include <protocols/bdx/BdxTransferServerDelegate.h>
24+
#include <protocols/bdx/DiagnosticLogs.h>
2125

22-
#import "MTRDeviceControllerFactory_Internal.h"
2326
#import "MTRDeviceController_Internal.h"
2427
#import "MTRError_Internal.h"
2528
#import "MTRLogging_Internal.h"
@@ -425,15 +428,15 @@ - (void)downloadLogFromNodeWithID:(NSNumber *)nodeID
425428
[download checkInteractionModelResponse:response error:error];
426429
};
427430

428-
auto * device = [controller deviceForNodeID:nodeID];
429-
auto * cluster = [[MTRClusterDiagnosticLogs alloc] initWithDevice:device endpointID:@(kDiagnosticLogsEndPoint) queue:queue];
431+
auto * device = [MTRBaseDevice deviceWithNodeID:nodeID controller:controller];
432+
auto * cluster = [[MTRBaseClusterDiagnosticLogs alloc] initWithDevice:device endpointID:@(kDiagnosticLogsEndPoint) queue:queue];
430433

431434
auto * params = [[MTRDiagnosticLogsClusterRetrieveLogsRequestParams alloc] init];
432435
params.intent = @(type);
433436
params.requestedProtocol = @(MTRDiagnosticLogsTransferProtocolBDX);
434437
params.transferFileDesignator = download.fileDesignator;
435438

436-
[cluster retrieveLogsRequestWithParams:params expectedValues:nil expectedValueInterval:nil completion:interactionModelDone];
439+
[cluster retrieveLogsRequestWithParams:params completion:interactionModelDone];
437440

438441
if (timeoutInSeconds > 0) {
439442
auto err = _bridge->StartBDXTransferTimeout(download, timeoutInSeconds);

0 commit comments

Comments
 (0)