Skip to content

Commit

Permalink
[OTA] Retry a CASE session establishment after session tear down (#16153
Browse files Browse the repository at this point in the history
)
  • Loading branch information
carol-apple authored Mar 14, 2022
1 parent 1126980 commit d22a557
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 15 deletions.
24 changes: 20 additions & 4 deletions src/app/clusters/ota-requestor/GenericOTARequestorDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,27 @@ bool GenericOTARequestorDriver::ProviderLocationsEqual(const ProviderLocationTyp

void GenericOTARequestorDriver::HandleError(UpdateFailureState state, CHIP_ERROR error) {}

void GenericOTARequestorDriver::HandleIdleState()
void GenericOTARequestorDriver::HandleIdleState(IdleStateReason reason)
{
// Default provider timer runs if and only if the OTARequestor's update state is kIdle.
// Must (re)start the timer every time we enter the kIdle state
StartDefaultProviderTimer();
switch (reason)
{
case IdleStateReason::kUnknown:
ChipLogProgress(SoftwareUpdate, "Unknown idle state reason so set the periodic timer for a next attempt");
StartDefaultProviderTimer();
break;
case IdleStateReason::kIdle:
// There is no current OTA update in progress so start the periodic query timer
StartDefaultProviderTimer();
break;
case IdleStateReason::kInvalidSession:
// An invalid session is detected which may be temporary so try to query again
ProviderLocationType providerLocation;
if (DetermineProviderLocation(providerLocation) == true)
{
DeviceLayer::SystemLayer().ScheduleLambda([this] { mRequestor->TriggerImmediateQueryInternal(); });
}
break;
}
}

void GenericOTARequestorDriver::UpdateAvailable(const UpdateDescription & update, System::Clock::Seconds32 delay)
Expand Down
2 changes: 1 addition & 1 deletion src/app/clusters/ota-requestor/GenericOTARequestorDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class GenericOTARequestorDriver : public OTARequestorDriver
bool CanConsent() override;
uint16_t GetMaxDownloadBlockSize() override;
void HandleError(UpdateFailureState state, CHIP_ERROR error) override;
void HandleIdleState() override;
void HandleIdleState(IdleStateReason reason) override;
void UpdateAvailable(const UpdateDescription & update, System::Clock::Seconds32 delay) override;
void UpdateNotFound(UpdateNotFoundReason reason, System::Clock::Seconds32 delay) override;
void UpdateDownloaded() override;
Expand Down
28 changes: 22 additions & 6 deletions src/app/clusters/ota-requestor/OTARequestor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,12 @@ void OTARequestor::OnQueryImageFailure(void * context, CHIP_ERROR error)

ChipLogError(SoftwareUpdate, "Received QueryImage failure response: %" CHIP_ERROR_FORMAT, error.Format());

// A previously valid CASE session may have become invalid
if (error == CHIP_ERROR_TIMEOUT)
{
ChipLogError(SoftwareUpdate, "CASE session may be invalid, tear down session");
requestorCore->DisconnectFromProvider();
error = CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY;
}

requestorCore->RecordErrorUpdateState(UpdateFailureState::kQuerying, error);
Expand Down Expand Up @@ -585,7 +587,21 @@ void OTARequestor::OnUpdateProgressChanged(Nullable<uint8_t> percent)
OtaRequestorServerSetUpdateStateProgress(percent);
}

void OTARequestor::RecordNewUpdateState(OTAUpdateStateEnum newState, OTAChangeReasonEnum reason)
IdleStateReason OTARequestor::MapErrorToIdleStateReason(CHIP_ERROR error)
{
if (error == CHIP_NO_ERROR)
{
return IdleStateReason::kIdle;
}
else if (error == CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY)
{
return IdleStateReason::kInvalidSession;
}

return IdleStateReason::kUnknown;
}

void OTARequestor::RecordNewUpdateState(OTAUpdateStateEnum newState, OTAChangeReasonEnum reason, CHIP_ERROR error)
{
// Set server UpdateState attribute
OtaRequestorServerSetUpdateState(newState);
Expand All @@ -607,12 +623,12 @@ void OTARequestor::RecordNewUpdateState(OTAUpdateStateEnum newState, OTAChangeRe
}
OtaRequestorServerOnStateTransition(mCurrentUpdateState, newState, reason, targetSoftwareVersion);

// Inform the driver that the OTARequestor has entered the kIdle state. A driver implementation
// may choose to restart the default provider timer in this case
if ((newState == OTAUpdateStateEnum::kIdle) && (mCurrentUpdateState != OTAUpdateStateEnum::kIdle))
{
// TODO: Make this API a general state change
mOtaRequestorDriver->HandleIdleState();
IdleStateReason idleStateReason = MapErrorToIdleStateReason(error);

// Inform the driver that the OTARequestor has entered the Idle state
mOtaRequestorDriver->HandleIdleState(idleStateReason);
}

mCurrentUpdateState = newState;
Expand All @@ -631,7 +647,7 @@ void OTARequestor::RecordErrorUpdateState(UpdateFailureState failureState, CHIP_
OtaRequestorServerOnDownloadError(mTargetVersion, imageProcessor->GetBytesDownloaded(), progressPercent, platformCode);

// Whenever an error occurs, always reset to Idle state
RecordNewUpdateState(OTAUpdateStateEnum::kIdle, reason);
RecordNewUpdateState(OTAUpdateStateEnum::kIdle, reason, error);
}

CHIP_ERROR OTARequestor::GenerateUpdateToken()
Expand Down
7 changes: 6 additions & 1 deletion src/app/clusters/ota-requestor/OTARequestor.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,15 @@ class OTARequestor : public OTARequestorInterface, public BDXDownloader::StateDe
*/
static void InitState(intptr_t context);

/**
* Map a CHIP_ERROR to an IdleStateReason enum type
*/
IdleStateReason MapErrorToIdleStateReason(CHIP_ERROR error);

/**
* Record the new update state by updating the corresponding server attribute and logging a StateTransition event
*/
void RecordNewUpdateState(OTAUpdateStateEnum newState, OTAChangeReasonEnum reason);
void RecordNewUpdateState(OTAUpdateStateEnum newState, OTAChangeReasonEnum reason, CHIP_ERROR error = CHIP_NO_ERROR);

/**
* Record the error update state by informing the driver of the error and calling `RecordNewUpdateState`
Expand Down
12 changes: 10 additions & 2 deletions src/app/clusters/ota-requestor/OTARequestorDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ enum class UpdateNotFoundReason
ConnectionFailed,
};

// The reasons for why the OTA Requestor has entered idle state
enum class IdleStateReason
{
kUnknown,
kIdle,
kInvalidSession,
};

// Interface class to abstract the OTA-related business logic. Each application
// must implement this interface. All calls must be non-blocking unless stated otherwise
class OTARequestorDriver
Expand All @@ -80,8 +88,8 @@ class OTARequestorDriver
/// Called when an error occurs at any OTA requestor operation
virtual void HandleError(UpdateFailureState state, CHIP_ERROR error) = 0;

// Called when the OTA Requestor enters the kIdle update state
virtual void HandleIdleState() = 0;
// Called when the OTA Requestor has entered the Idle state for which the driver may need to take various actions
virtual void HandleIdleState(IdleStateReason reason) = 0;

/// Called when the latest query found a software update
virtual void UpdateAvailable(const UpdateDescription & update, System::Clock::Seconds32 delay) = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/app/clusters/ota-requestor/ota-requestor-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ void OtaRequestorServerOnStateTransition(OTAUpdateStateEnum previousState, OTAUp
{
if (previousState == newState)
{
ChipLogError(Zcl, "Previous state and new state are the same, no event to log");
ChipLogError(Zcl, "Previous state and new state are the same (%d), no event to log", to_underlying(newState));
return;
}

Expand Down

0 comments on commit d22a557

Please sign in to comment.