Skip to content

Commit f779369

Browse files
Darwin: Ensure we tell the OTA delegate when a transfer ends (#34190)
* Darwin: Tweak OTA provider test to make it easier to extend Use AssertIdentical for obejct identity tests Fulfill expectations at the start of callback blocks before calling more methods * Darwin: Ensure we tell the OTA delegate when a transfer ends Ensure we call handleBDXTransferSessionEndForNodeID:... if we have called handleBDXTransferSessionBeginForNodeID:..., even if the session is reset via an error code path. * Remove TODO clarified in review * restyle
1 parent 896d771 commit f779369

File tree

2 files changed

+52
-34
lines changed

2 files changed

+52
-34
lines changed

src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm

+32-26
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ CHIP_ERROR Shutdown()
104104
VerifyOrReturnError(mExchangeMgr != nullptr, CHIP_ERROR_INCORRECT_STATE);
105105

106106
mExchangeMgr->UnregisterUnsolicitedMessageHandlerForProtocol(Protocols::BDX::Id);
107-
ResetState();
107+
ResetState(CHIP_ERROR_CANCELLED);
108108

109109
mExchangeMgr = nullptr;
110110
mSystemLayer = nullptr;
@@ -117,18 +117,35 @@ void ControllerShuttingDown(MTRDeviceController * controller)
117117
assertChipStackLockedByCurrentThread();
118118

119119
if (mInitialized && mFabricIndex.Value() == controller.fabricIndex) {
120-
ResetState();
120+
ResetState(CHIP_ERROR_CANCELLED);
121121
}
122122
}
123123

124-
void ResetState()
124+
void ResetState(CHIP_ERROR error)
125125
{
126126
assertChipStackLockedByCurrentThread();
127127
if (mNodeId.HasValue() && mFabricIndex.HasValue()) {
128128
ChipLogProgress(Controller,
129129
"Resetting state for OTA Provider; no longer providing an update for node id 0x" ChipLogFormatX64
130130
", fabric index %u",
131131
ChipLogValueX64(mNodeId.Value()), mFabricIndex.Value());
132+
133+
if (mTransferStarted) {
134+
auto controller = [MTRDeviceControllerFactory.sharedInstance runningControllerForFabricIndex:mFabricIndex.Value()];
135+
if (controller) {
136+
auto nodeId = @(mNodeId.Value());
137+
auto strongDelegate = mDelegate;
138+
if ([strongDelegate respondsToSelector:@selector(handleBDXTransferSessionEndForNodeID:controller:error:)]) {
139+
dispatch_async(mDelegateNotificationQueue, ^{
140+
[strongDelegate handleBDXTransferSessionEndForNodeID:nodeId
141+
controller:controller
142+
error:[MTRError errorForCHIPErrorCode:error]];
143+
});
144+
}
145+
} else {
146+
ChipLogError(Controller, "Not notifying delegate of BDX Transfer Session End, controller is not running");
147+
}
148+
}
132149
} else {
133150
ChipLogProgress(Controller, "Resetting state for OTA Provider");
134151
}
@@ -153,6 +170,7 @@ void ResetState()
153170
mDelegateNotificationQueue = nil;
154171

155172
mInitialized = false;
173+
mTransferStarted = false;
156174
}
157175

158176
private:
@@ -162,7 +180,7 @@ void ResetState()
162180
static void HandleBdxInitReceivedTimeoutExpired(chip::System::Layer * systemLayer, void * state)
163181
{
164182
VerifyOrReturn(state != nullptr);
165-
static_cast<BdxOTASender *>(state)->ResetState();
183+
static_cast<BdxOTASender *>(state)->ResetState(CHIP_ERROR_TIMEOUT);
166184
}
167185

168186
CHIP_ERROR OnMessageToSend(TransferSession::OutputEvent & event)
@@ -188,12 +206,12 @@ CHIP_ERROR OnMessageToSend(TransferSession::OutputEvent & event)
188206
if (err != CHIP_NO_ERROR) {
189207
mExchangeCtx->Close();
190208
mExchangeCtx = nullptr;
191-
ResetState();
192-
} else if (event.msgTypeData.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport)) {
209+
ResetState(err);
210+
} else if (msgTypeData.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport)) {
193211
// If the send was successful for a status report, since we are not expecting a response the exchange context is
194212
// already closed. We need to null out the reference to avoid having a dangling pointer.
195213
mExchangeCtx = nullptr;
196-
ResetState();
214+
ResetState(CHIP_ERROR_INTERNAL);
197215
}
198216
return err;
199217
}
@@ -258,8 +276,8 @@ CHIP_ERROR OnTransferSessionBegin(TransferSession::OutputEvent & event)
258276
}];
259277
};
260278

279+
mTransferStarted = true;
261280
auto nodeId = @(mNodeId.Value());
262-
263281
auto strongDelegate = mDelegate;
264282
dispatch_async(mDelegateNotificationQueue, ^{
265283
if ([strongDelegate respondsToSelector:@selector(handleBDXTransferSessionBeginForNodeID:controller:fileDesignator:offset:completion:)]) {
@@ -294,20 +312,7 @@ CHIP_ERROR OnTransferSessionEnd(TransferSession::OutputEvent & event)
294312
error = CHIP_ERROR_INTERNAL;
295313
}
296314

297-
auto * controller = [[MTRDeviceControllerFactory sharedInstance] runningControllerForFabricIndex:mFabricIndex.Value()];
298-
VerifyOrReturnError(controller != nil, CHIP_ERROR_INCORRECT_STATE);
299-
auto nodeId = @(mNodeId.Value());
300-
301-
auto strongDelegate = mDelegate;
302-
if ([strongDelegate respondsToSelector:@selector(handleBDXTransferSessionEndForNodeID:controller:error:)]) {
303-
dispatch_async(mDelegateNotificationQueue, ^{
304-
[strongDelegate handleBDXTransferSessionEndForNodeID:nodeId
305-
controller:controller
306-
error:[MTRError errorForCHIPErrorCode:error]];
307-
});
308-
}
309-
310-
ResetState();
315+
ResetState(error); // will notify the delegate
311316
return CHIP_NO_ERROR;
312317
}
313318

@@ -438,7 +443,7 @@ CHIP_ERROR ConfigureState(chip::FabricIndex fabricIndex, chip::NodeId nodeId)
438443
VerifyOrReturnError(mFabricIndex.Value() == fabricIndex && mNodeId.Value() == nodeId, CHIP_ERROR_BUSY);
439444

440445
// Reset stale connection from the same Node if exists.
441-
ResetState();
446+
ResetState(CHIP_ERROR_CANCELLED);
442447
}
443448

444449
auto * controller = [[MTRDeviceControllerFactory sharedInstance] runningControllerForFabricIndex:fabricIndex];
@@ -466,6 +471,7 @@ CHIP_ERROR ConfigureState(chip::FabricIndex fabricIndex, chip::NodeId nodeId)
466471
}
467472

468473
bool mInitialized = false;
474+
bool mTransferStarted = false;
469475
Optional<FabricIndex> mFabricIndex;
470476
Optional<NodeId> mNodeId;
471477
id<MTROTAProviderDelegate> mDelegate = nil;
@@ -489,7 +495,7 @@ CHIP_ERROR ConfigureState(chip::FabricIndex fabricIndex, chip::NodeId nodeId)
489495

490496
MTROTAProviderDelegateBridge::~MTROTAProviderDelegateBridge()
491497
{
492-
gOtaSender->ResetState();
498+
gOtaSender->ResetState(CHIP_ERROR_CANCELLED);
493499
Clusters::OTAProvider::SetDelegate(kOtaProviderEndpoint, nullptr);
494500
}
495501

@@ -685,7 +691,7 @@ bool GetPeerNodeInfo(CommandHandler * commandHandler, const ConcreteCommandPath
685691
handle.Release();
686692
// We need to reset state here to clean up any initialization we might have done including starting the BDX
687693
// timeout timer while preparing for transfer if any failure occurs afterwards.
688-
gOtaSender->ResetState();
694+
gOtaSender->ResetState(err);
689695
return;
690696
}
691697

@@ -696,7 +702,7 @@ bool GetPeerNodeInfo(CommandHandler * commandHandler, const ConcreteCommandPath
696702
LogErrorOnFailure(err);
697703
handler->AddStatus(cachedCommandPath, StatusIB(err).mStatus);
698704
handle.Release();
699-
gOtaSender->ResetState();
705+
gOtaSender->ResetState(err);
700706
return;
701707
}
702708
delegateResponse.imageURI.SetValue(uri);

src/darwin/Framework/CHIPTests/MTROTAProviderTests.m

+20-8
Original file line numberDiff line numberDiff line change
@@ -818,13 +818,15 @@ - (void)test003_ReceiveQueryImageRequestWhileHandlingBDX_RespondImplicitBusy
818818
XCTestExpectation * queryExpectation1 = [self expectationWithDescription:@"handleQueryImageForNodeID called first time"];
819819
XCTestExpectation * queryExpectation2 = [self expectationWithDescription:@"handleQueryImageForNodeID called second time"];
820820
XCTestExpectation * queryExpectation3 = [self expectationWithDescription:@"handleQueryImageForNodeID called third time"];
821+
XCTestExpectation * transferEndExpectation = [self expectationWithDescription:@"handleBDXTransferSessionEndForNodeID called"];
821822

822823
const uint16_t busyDelay = 1; // 1 second
823824
NSString * fakeImageURI = @"No such image, really";
824825

825826
__block QueryImageHandler handleThirdQuery;
826827
sOTAProviderDelegate.queryImageHandler = ^(NSNumber * nodeID, MTRDeviceController * controller,
827828
MTROTASoftwareUpdateProviderClusterQueryImageParams * params, QueryImageCompletion completion) {
829+
[queryExpectation1 fulfill];
828830
XCTAssertEqualObjects(nodeID, @(kDeviceId1));
829831
XCTAssertEqual(controller, sController);
830832
[sOTAProviderDelegate respondAvailableWithDelay:@(0)
@@ -833,23 +835,32 @@ - (void)test003_ReceiveQueryImageRequestWhileHandlingBDX_RespondImplicitBusy
833835
softwareVersion:kUpdatedSoftwareVersion_5
834836
softwareVersionString:kUpdatedSoftwareVersionString_5
835837
completion:completion];
836-
[queryExpectation1 fulfill];
837838
};
838839
sOTAProviderDelegate.transferBeginHandler = ^(NSNumber * nodeID, MTRDeviceController * controller, NSString * fileDesignator,
839840
NSNumber * offset, MTRStatusCompletion outerCompletion) {
841+
sOTAProviderDelegate.transferBeginHandler = nil;
842+
// Now that we've begun a transfer, we expect to be told when it ends, even if it's due to an error
843+
sOTAProviderDelegate.transferEndHandler = ^(NSNumber * nodeID, MTRDeviceController * controller, NSError * _Nullable error) {
844+
[transferEndExpectation fulfill];
845+
sOTAProviderDelegate.transferEndHandler = nil;
846+
XCTAssertEqualObjects(nodeID, @(kDeviceId1));
847+
XCTAssertIdentical(controller, sController);
848+
XCTAssertNotNil(error); // we cancelled the transfer, so there should be an error
849+
};
850+
840851
XCTAssertEqualObjects(nodeID, @(kDeviceId1));
841-
XCTAssertEqual(controller, sController);
852+
XCTAssertIdentical(controller, sController);
842853

843854
// Don't actually respond until the second requestor has queried us for
844855
// an image. We need to reset queryImageHandler here, so we can close
845856
// over outerCompletion.
846857
sOTAProviderDelegate.queryImageHandler = ^(NSNumber * nodeID, MTRDeviceController * controller,
847858
MTROTASoftwareUpdateProviderClusterQueryImageParams * params, QueryImageCompletion innerCompletion) {
859+
[queryExpectation2 fulfill];
848860
sOTAProviderDelegate.queryImageHandler = handleThirdQuery;
849-
sOTAProviderDelegate.transferBeginHandler = nil;
850861

851862
XCTAssertEqualObjects(nodeID, @(kDeviceId2));
852-
XCTAssertEqual(controller, sController);
863+
XCTAssertIdentical(controller, sController);
853864

854865
// We respond UpdateAvailable, but since we are in the middle of
855866
// handling OTA for device1 we expect the requestor to get Busy and
@@ -860,28 +871,29 @@ - (void)test003_ReceiveQueryImageRequestWhileHandlingBDX_RespondImplicitBusy
860871
softwareVersion:kUpdatedSoftwareVersion_5
861872
softwareVersionString:kUpdatedSoftwareVersionString_5
862873
completion:innerCompletion];
874+
875+
// Cancel the transfer with device1
863876
[sOTAProviderDelegate respondErrorWithCompletion:outerCompletion];
864-
[queryExpectation2 fulfill];
865877
};
866878

867879
announceResponseExpectation2 = [self announceProviderToDevice:device2];
868880
};
869881

870882
handleThirdQuery = ^(NSNumber * nodeID, MTRDeviceController * controller,
871883
MTROTASoftwareUpdateProviderClusterQueryImageParams * params, QueryImageCompletion completion) {
884+
[queryExpectation3 fulfill];
872885
XCTAssertEqualObjects(nodeID, @(kDeviceId2));
873-
XCTAssertEqual(controller, sController);
886+
XCTAssertIdentical(controller, sController);
874887

875888
[sOTAProviderDelegate respondNotAvailableWithCompletion:completion];
876-
[queryExpectation3 fulfill];
877889
};
878890

879891
// Advertise ourselves as an OTA provider.
880892
XCTestExpectation * announceResponseExpectation1 = [self announceProviderToDevice:device1];
881893

882894
// Make sure we get our queries in order. Give it a bit more time, because
883895
// there will be a delay between the two queries.
884-
[self waitForExpectations:@[ queryExpectation1, queryExpectation2, queryExpectation3 ]
896+
[self waitForExpectations:@[ queryExpectation1, queryExpectation2, transferEndExpectation, queryExpectation3 ]
885897
timeout:(kTimeoutInSeconds + busyDelay * 3)
886898
enforceOrder:YES];
887899

0 commit comments

Comments
 (0)