Skip to content

Commit

Permalink
[Android] Return ConnectionFailureException which contains the connec…
Browse files Browse the repository at this point in the history
…tion state… (project-chip#31149)

* Return ConnectionFailureException which contains the connection state info in onConnectionFailure

* Update src/app/CASESessionManager.h

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Address review comments

* Allow onFailure and onSetupFailure to be null

* Update src/app/CASESessionManager.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Address review comments

---------

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
  • Loading branch information
yufengwangca and bzbarsky-apple authored Dec 22, 2023
1 parent 6484d4d commit b364ee6
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 10 deletions.
68 changes: 66 additions & 2 deletions src/app/CASESessionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,56 @@ void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Cal
uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry
#endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
)
{
FindOrEstablishSessionHelper(peerId, onConnection, onFailure, nullptr
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
attemptCount, onRetry
#endif
);
}

void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
Callback::Callback<OperationalSessionSetup::OnSetupFailure> * onSetupFailure
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry
#endif
)
{
FindOrEstablishSessionHelper(peerId, onConnection, nullptr, onSetupFailure
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
attemptCount, onRetry
#endif
);
}

void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
nullptr_t
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry
#endif
)
{
FindOrEstablishSessionHelper(peerId, onConnection, nullptr, nullptr
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
attemptCount, onRetry
#endif
);
}

void CASESessionManager::FindOrEstablishSessionHelper(const ScopedNodeId & peerId,
Callback::Callback<OnDeviceConnected> * onConnection,
Callback::Callback<OnDeviceConnectionFailure> * onFailure,
Callback::Callback<OperationalSessionSetup::OnSetupFailure> * onSetupFailure
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry
#endif
)
{
ChipLogDetail(CASESessionManager, "FindOrEstablishSession: PeerId = [%d:" ChipLogFormatX64 "]", peerId.GetFabricIndex(),
ChipLogValueX64(peerId.GetNodeId()));
Expand All @@ -45,7 +95,6 @@ void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Cal
if (session == nullptr)
{
ChipLogDetail(CASESessionManager, "FindOrEstablishSession: No existing OperationalSessionSetup instance found");

session = mConfig.sessionSetupPool->Allocate(mConfig.sessionInitParams, mConfig.clientPool, peerId, this);

if (session == nullptr)
Expand All @@ -54,6 +103,13 @@ void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Cal
{
onFailure->mCall(onFailure->mContext, peerId, CHIP_ERROR_NO_MEMORY);
}

if (onSetupFailure != nullptr)
{
OperationalSessionSetup::ConnnectionFailureInfo failureInfo(peerId, CHIP_ERROR_NO_MEMORY,
SessionEstablishmentStage::kUnknown);
onSetupFailure->mCall(onSetupFailure->mContext, failureInfo);
}
return;
}
}
Expand All @@ -66,7 +122,15 @@ void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Cal
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES

session->Connect(onConnection, onFailure);
if (onFailure != nullptr)
{
session->Connect(onConnection, onFailure);
}

if (onSetupFailure != nullptr)
{
session->Connect(onConnection, onSetupFailure);
}
}

void CASESessionManager::ReleaseSessionsForFabric(FabricIndex fabricIndex)
Expand Down
65 changes: 65 additions & 0 deletions src/app/CASESessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,63 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess
#endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
);

/**
* Find an existing session for the given node ID or trigger a new session request.
*
* The caller can optionally provide `onConnection` and `onSetupFailure`
* callback objects. If provided, these will be used to inform the caller about successful or
* failed connection establishment.
*
* If the connection is already established, the `onConnection` callback will be immediately called,
* before `FindOrEstablishSession` returns.
*
* The `onSetupFailure` callback may be called before the `FindOrEstablishSession`
* call returns, for error cases that are detected synchronously.
*
* The `attemptCount` parameter can be used to automatically retry multiple times if session setup is
* not successful.
*
* @param peerId The node ID to find or establish a session with.
* @param onConnection A callback to be called upon successful connection establishment.
* @param onSetupFailure A callback to be called upon an extended device connection failure.
* @param attemptCount The number of retry attempts if session setup fails (default is 1).
* @param onRetry A callback to be called on a retry attempt (enabled by a config flag).
*/
void FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
Callback::Callback<OperationalSessionSetup::OnSetupFailure> * onSetupFailure
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
uint8_t attemptCount = 1, Callback::Callback<OnDeviceConnectionRetry> * onRetry = nullptr
#endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
);

/**
* Find an existing session for the given node ID or trigger a new session request.
*
* The caller can optionally provide `onConnection`
* callback objects. If provided, these will be used to inform the caller about successful connection establishment.
*
* If the connection is already established, the `onConnection` callback will be immediately called,
* before `FindOrEstablishSession` returns.
*
* The `attemptCount` parameter can be used to automatically retry multiple times if session setup is
* not successful.
*
* This function allows passing 'nullptr' for the error handler to compile, which is useful in scenarios where error
* handling is not needed.
*
* @param peerId The node ID to find or establish a session with.
* @param onConnection A callback to be called upon successful connection establishment.
* @param attemptCount The number of retry attempts if session setup fails (default is 1).
* @param onRetry A callback to be called on a retry attempt (enabled by a config flag).
*/
void FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection, nullptr_t
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
,
uint8_t attemptCount = 1, Callback::Callback<OnDeviceConnectionRetry> * onRetry = nullptr
#endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
);

void ReleaseSessionsForFabric(FabricIndex fabricIndex);

void ReleaseAllSessions();
Expand All @@ -112,6 +169,14 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess

Optional<SessionHandle> FindExistingSession(const ScopedNodeId & peerId) const;

void FindOrEstablishSessionHelper(const ScopedNodeId & peerId, Callback::Callback<OnDeviceConnected> * onConnection,
Callback::Callback<OnDeviceConnectionFailure> * onFailure,
Callback::Callback<OperationalSessionSetup::OnSetupFailure> * onSetupFailure,
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
uint8_t attemptCount, Callback::Callback<OnDeviceConnectionRetry> * onRetry
#endif
);

CASESessionManagerConfig mConfig;
};

Expand Down
28 changes: 26 additions & 2 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,11 @@ class DLL_EXPORT DeviceController : public AbstractDnssdDiscoveryController
* This function finds the device corresponding to deviceId, and establishes
* a CASE session with it.
*
* Once the CASE session is successfully established the `onConnectedDevice`
* Once the CASE session is successfully established the `onConnection`
* callback is called. This can happen before GetConnectedDevice returns if
* there is an existing CASE session.
*
* If a CASE sessions fails to be established, the `onError` callback will
* If a CASE sessions fails to be established, the `onFailure` callback will
* be called. This can also happen before GetConnectedDevice returns.
*
* An error return from this function means that neither callback has been
Expand All @@ -238,6 +238,30 @@ class DLL_EXPORT DeviceController : public AbstractDnssdDiscoveryController
return CHIP_NO_ERROR;
}

/**
* This function finds the device corresponding to deviceId, and establishes
* a CASE session with it.
*
* Once the CASE session is successfully established the `onConnection`
* callback is called. This can happen before GetConnectedDevice returns if
* there is an existing CASE session.
*
* If a CASE sessions fails to be established, the `onSetupFailure` callback will
* be called. This can also happen before GetConnectedDevice returns.
*
* An error return from this function means that neither callback has been
* called yet, and neither callback will be called in the future.
*/
CHIP_ERROR
GetConnectedDevice(NodeId peerNodeId, Callback::Callback<OnDeviceConnected> * onConnection,
chip::Callback::Callback<OperationalSessionSetup::OnSetupFailure> * onSetupFailure)
{
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
mSystemState->CASESessionMgr()->FindOrEstablishSession(ScopedNodeId(peerNodeId, GetFabricIndex()), onConnection,
onSetupFailure);
return CHIP_NO_ERROR;
}

/**
* @brief
* Compute a PASE verifier and passcode ID for the desired setup pincode.
Expand Down
10 changes: 6 additions & 4 deletions src/controller/java/AndroidCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/
#include "AndroidCallbacks.h"
#include <controller/java/AndroidConnectionFailureExceptions.h>
#include <controller/java/AndroidControllerExceptions.h>
#ifdef USE_JAVA_TLV_ENCODE_DECODE
#include <controller/java/CHIPAttributeTLVValueDecoder.h>
Expand Down Expand Up @@ -114,7 +115,8 @@ void GetConnectedDeviceCallback::OnDeviceConnectedFn(void * context, Messaging::
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
}

void GetConnectedDeviceCallback::OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
void GetConnectedDeviceCallback::OnDeviceConnectionFailureFn(void * context,
const OperationalSessionSetup::ConnnectionFailureInfo & failureInfo)
{
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread"));
Expand All @@ -135,15 +137,15 @@ void GetConnectedDeviceCallback::OnDeviceConnectionFailureFn(void * context, con
VerifyOrReturn(failureMethod != nullptr, ChipLogError(Controller, "Could not find onConnectionFailure method"));

jthrowable exception;
CHIP_ERROR err = AndroidControllerExceptions::GetInstance().CreateAndroidControllerException(env, ErrorStr(error),
error.AsInteger(), exception);
CHIP_ERROR err = AndroidConnectionFailureExceptions::GetInstance().CreateAndroidConnectionFailureException(
env, failureInfo.error.Format(), failureInfo.error.AsInteger(), failureInfo.sessionStage, exception);
VerifyOrReturn(
err == CHIP_NO_ERROR,
ChipLogError(Controller,
"Unable to create AndroidControllerException on GetConnectedDeviceCallback::OnDeviceConnectionFailureFn: %s",
ErrorStr(err)));
DeviceLayer::StackUnlock unlock;
env->CallVoidMethod(javaCallback, failureMethod, peerId.GetNodeId(), exception);
env->CallVoidMethod(javaCallback, failureMethod, failureInfo.peerId.GetNodeId(), exception);
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
}

Expand Down
4 changes: 2 additions & 2 deletions src/controller/java/AndroidCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ struct GetConnectedDeviceCallback
~GetConnectedDeviceCallback();

static void OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle);
static void OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error);
static void OnDeviceConnectionFailureFn(void * context, const OperationalSessionSetup::ConnnectionFailureInfo & failureInfo);

Callback::Callback<OnDeviceConnected> mOnSuccess;
Callback::Callback<OnDeviceConnectionFailure> mOnFailure;
Callback::Callback<OperationalSessionSetup::OnSetupFailure> mOnFailure;
JniGlobalReference mWrapperCallbackRef;
JniGlobalReference mJavaCallbackRef;
};
Expand Down
44 changes: 44 additions & 0 deletions src/controller/java/AndroidConnectionFailureExceptions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
*
* Copyright (c) 2023 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.
*/

#include "AndroidConnectionFailureExceptions.h"

#include <lib/core/CHIPError.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>

namespace chip {

CHIP_ERROR AndroidConnectionFailureExceptions::CreateAndroidConnectionFailureException(JNIEnv * env, const char * message,
uint32_t errorCode,
SessionEstablishmentStage state,
jthrowable & outEx)
{
jclass controllerExceptionCls;
CHIP_ERROR err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/ConnectionFailureException",
controllerExceptionCls);
VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_JNI_ERROR_TYPE_NOT_FOUND);

jmethodID exceptionConstructor = env->GetMethodID(controllerExceptionCls, "<init>", "(JILjava/lang/String;)V");
outEx = static_cast<jthrowable>(env->NewObject(controllerExceptionCls, exceptionConstructor, static_cast<jlong>(errorCode),
static_cast<jint>(state), env->NewStringUTF(message)));
VerifyOrReturnError(outEx != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND);
return CHIP_NO_ERROR;
}

} // namespace chip
47 changes: 47 additions & 0 deletions src/controller/java/AndroidConnectionFailureExceptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
*
* Copyright (c) 2023 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.
*/

#pragma once

#include <app/OperationalSessionSetup.h>
#include <jni.h>
#include <lib/core/CHIPError.h>

namespace chip {
class AndroidConnectionFailureExceptions
{
public:
AndroidConnectionFailureExceptions(const AndroidConnectionFailureExceptions &) = delete;
AndroidConnectionFailureExceptions(const AndroidConnectionFailureExceptions &&) = delete;
AndroidConnectionFailureExceptions & operator=(const AndroidConnectionFailureExceptions &) = delete;

static AndroidConnectionFailureExceptions & GetInstance()
{
static AndroidConnectionFailureExceptions androidConnectionFailureExceptions;
return androidConnectionFailureExceptions;
}

/**
* Creates a Java ConnectionFailureException object in outEx.
*/
CHIP_ERROR CreateAndroidConnectionFailureException(JNIEnv * env, const char * message, uint32_t errorCode,
SessionEstablishmentStage state, jthrowable & outEx);

private:
AndroidConnectionFailureExceptions() {}
};
} // namespace chip
3 changes: 3 additions & 0 deletions src/controller/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ shared_library("jni") {
"AndroidClusterExceptions.h",
"AndroidCommissioningWindowOpener.cpp",
"AndroidCommissioningWindowOpener.h",
"AndroidConnectionFailureExceptions.cpp",
"AndroidConnectionFailureExceptions.h",
"AndroidControllerExceptions.cpp",
"AndroidControllerExceptions.h",
"AndroidCurrentFabricRemover.cpp",
Expand Down Expand Up @@ -439,6 +441,7 @@ android_library("java") {
"src/chip/devicecontroller/ChipCommandType.java",
"src/chip/devicecontroller/ChipDeviceController.java",
"src/chip/devicecontroller/ChipDeviceControllerException.java",
"src/chip/devicecontroller/ConnectionFailureException.java",
"src/chip/devicecontroller/ControllerParams.java",
"src/chip/devicecontroller/DeviceAttestationDelegate.java",
"src/chip/devicecontroller/DiscoveredDevice.java",
Expand Down
Loading

0 comments on commit b364ee6

Please sign in to comment.