[Android] Implement LIT ICD for subscription (#33152)
* Implement android LIT ICD subscribe
* Refactoring ChipICDClient
* Fix fabric Index, remoteID issue
* Restyled by whitespace
* Restyled by google-java-format
* Restyled by clang-format
* Restyled by gn
* remove Unused API
* Add Kotlin ICD Client Info
* Fix build error
---------
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja b/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja
index b391d09..954bd7d 100644
--- a/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja
+++ b/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja
@@ -219,7 +219,9 @@
int maxInterval) {
ReportCallbackJni jniCallback = new ReportCallbackJni(callback, callback, callback);
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, attributeId);
- ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null);
+ int fabricIndex = ChipInteractionClient.getFabricIndex(devicePtr);
+ long deviceId = ChipInteractionClient.getRemoteDeviceId(devicePtr);
+ ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null, ChipICDClient.isPeerICDClient(fabricIndex, deviceId));
}
protected void invoke(
diff --git a/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java b/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java
index b574271..037870e 100644
--- a/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java
+++ b/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java
@@ -142,7 +142,9 @@
int maxInterval) {
ReportCallbackJni jniCallback = new ReportCallbackJni(callback, callback, callback);
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, attributeId);
- ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null);
+ int fabricIndex = ChipInteractionClient.getFabricIndex(devicePtr);
+ long deviceId = ChipInteractionClient.getRemoteDeviceId(devicePtr);
+ ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null, ChipICDClient.isPeerICDClient(fabricIndex, deviceId));
}
protected void invoke(
diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp
index c5b3863..1576e58 100644
--- a/src/controller/java/AndroidDeviceControllerWrapper.cpp
+++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp
@@ -30,6 +30,7 @@
#include <lib/support/JniTypeWrappers.h>
#include <controller/CHIPDeviceControllerFactory.h>
+#include <controller/java/AndroidICDClient.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <lib/core/TLV.h>
@@ -185,7 +186,7 @@
chip::Credentials::SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));
}
- *errInfoOnFailure = wrapper->mICDClientStorage.Init(wrapperStorage, &wrapper->mSessionKeystore);
+ *errInfoOnFailure = getICDClientStorage()->Init(wrapperStorage, &wrapper->mSessionKeystore);
if (*errInfoOnFailure != CHIP_NO_ERROR)
{
ChipLogError(Controller, "ICD Client Storage failure");
@@ -401,12 +402,12 @@
*errInfoOnFailure = chip::Credentials::SetSingleIpkEpochKey(
&wrapper->mGroupDataProvider, wrapper->Controller()->GetFabricIndex(), ipkSpan, compressedFabricIdSpan);
- wrapper->getICDClientStorage()->UpdateFabricList(wrapper->Controller()->GetFabricIndex());
+ getICDClientStorage()->UpdateFabricList(wrapper->Controller()->GetFabricIndex());
auto engine = chip::app::InteractionModelEngine::GetInstance();
- *errInfoOnFailure = wrapper->mCheckInDelegate.Init(&wrapper->mICDClientStorage, engine);
+ *errInfoOnFailure = wrapper->mCheckInDelegate.Init(getICDClientStorage(), engine);
*errInfoOnFailure = wrapper->mCheckInHandler.Init(DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(),
- &wrapper->mICDClientStorage, &wrapper->mCheckInDelegate, engine);
+ getICDClientStorage(), &wrapper->mCheckInDelegate, engine);
memset(ipkBuffer.data(), 0, ipkBuffer.size());
@@ -725,7 +726,7 @@
if (error != CHIP_NO_ERROR && mDeviceIsICD)
{
- CHIP_ERROR deleteEntryError = mICDClientStorage.DeleteEntry(ScopedNodeId(deviceId, Controller()->GetFabricIndex()));
+ CHIP_ERROR deleteEntryError = getICDClientStorage()->DeleteEntry(ScopedNodeId(deviceId, Controller()->GetFabricIndex()));
if (deleteEntryError != CHIP_NO_ERROR)
{
ChipLogError(chipTool, "Failed to delete ICD entry: %" CHIP_ERROR_FORMAT, deleteEntryError.Format());
@@ -1003,10 +1004,10 @@
ByteSpan symmetricKey = mAutoCommissioner.GetCommissioningParameters().GetICDSymmetricKey().Value();
- err = mICDClientStorage.SetKey(clientInfo, symmetricKey);
+ err = getICDClientStorage()->SetKey(clientInfo, symmetricKey);
if (err == CHIP_NO_ERROR)
{
- err = mICDClientStorage.StoreEntry(clientInfo);
+ err = getICDClientStorage()->StoreEntry(clientInfo);
}
if (err == CHIP_NO_ERROR)
@@ -1015,7 +1016,7 @@
}
else
{
- mICDClientStorage.RemoveKey(clientInfo);
+ getICDClientStorage()->RemoveKey(clientInfo);
ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(icdNodeId),
err.AsString());
}
diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h
index 3acf169..51beae2 100644
--- a/src/controller/java/AndroidDeviceControllerWrapper.h
+++ b/src/controller/java/AndroidDeviceControllerWrapper.h
@@ -212,8 +212,6 @@
CHIP_ERROR FinishOTAProvider();
- chip::app::DefaultICDClientStorage * getICDClientStorage() { return &mICDClientStorage; }
-
CHIP_ERROR SetICDCheckInDelegate(jobject checkInDelegate);
private:
@@ -228,7 +226,6 @@
// TODO: This may need to be injected as a SessionKeystore*
chip::Crypto::RawKeySessionKeystore mSessionKeystore;
- chip::app::DefaultICDClientStorage mICDClientStorage;
chip::app::AndroidCheckInDelegate mCheckInDelegate;
chip::app::CheckInHandler mCheckInHandler;
diff --git a/src/controller/java/AndroidICDClient.cpp b/src/controller/java/AndroidICDClient.cpp
new file mode 100644
index 0000000..83cb522
--- /dev/null
+++ b/src/controller/java/AndroidICDClient.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file
+ * Implementation of ICD Client API for Android Platform
+ *
+ */
+
+#include "AndroidICDClient.h"
+
+#include <app/icd/client/ICDClientInfo.h>
+
+chip::app::DefaultICDClientStorage sICDClientStorage;
+
+jobject getICDClientInfo(JNIEnv * env, const char * icdClientInfoSign, jint jFabricIndex)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ jobject jInfo = nullptr;
+ chip::app::ICDClientInfo info;
+ chip::FabricIndex fabricIndex = static_cast<chip::FabricIndex>(jFabricIndex);
+
+ ChipLogProgress(Controller, "getICDClientInfo(%u) called", fabricIndex);
+
+ err = chip::JniReferences::GetInstance().CreateArrayList(jInfo);
+ VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
+ ChipLogError(Controller, "CreateArrayList failed!: %" CHIP_ERROR_FORMAT, err.Format()));
+
+ auto iter = getICDClientStorage()->IterateICDClientInfo();
+ VerifyOrReturnValue(iter != nullptr, nullptr, ChipLogError(Controller, "IterateICDClientInfo failed!"));
+ chip::app::DefaultICDClientStorage::ICDClientInfoIteratorWrapper clientInfoIteratorWrapper(iter);
+
+ jmethodID constructor;
+ jclass infoClass;
+ chip::JniLocalReferenceScope scope(env);
+
+ err = chip::JniReferences::GetInstance().GetLocalClassRef(env, icdClientInfoSign, infoClass);
+ VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
+ ChipLogError(Controller, "Find ICDClientInfo class: %" CHIP_ERROR_FORMAT, err.Format()));
+
+ env->ExceptionClear();
+ constructor = env->GetMethodID(infoClass, "<init>", "(JJJJ[B[B)V");
+ VerifyOrReturnValue(constructor != nullptr, nullptr, ChipLogError(Controller, "Find GetMethodID error!"));
+
+ while (iter->Next(info))
+ {
+ jbyteArray jIcdAesKey = nullptr;
+ jbyteArray jIcdHmacKey = nullptr;
+ jobject jICDClientInfo = nullptr;
+
+ if (info.peer_node.GetFabricIndex() != fabricIndex)
+ {
+ continue;
+ }
+
+ err = chip::JniReferences::GetInstance().N2J_ByteArray(env,
+ info.aes_key_handle.As<chip::Crypto::Symmetric128BitsKeyByteArray>(),
+ chip::Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, jIcdAesKey);
+ VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
+ ChipLogError(Controller, "ICD AES KEY N2J_ByteArray error!: %" CHIP_ERROR_FORMAT, err.Format()));
+
+ err = chip::JniReferences::GetInstance().N2J_ByteArray(
+ env, info.hmac_key_handle.As<chip::Crypto::Symmetric128BitsKeyByteArray>(),
+ chip::Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, jIcdHmacKey);
+ VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
+ ChipLogError(Controller, "ICD HMAC KEY N2J_ByteArray error!: %" CHIP_ERROR_FORMAT, err.Format()));
+
+ jICDClientInfo = (jobject) env->NewObject(infoClass, constructor, static_cast<jlong>(info.peer_node.GetNodeId()),
+ static_cast<jlong>(info.start_icd_counter), static_cast<jlong>(info.offset),
+ static_cast<jlong>(info.monitored_subject), jIcdAesKey, jIcdHmacKey);
+
+ err = chip::JniReferences::GetInstance().AddToList(jInfo, jICDClientInfo);
+ VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
+ ChipLogError(Controller, "AddToList error!: %" CHIP_ERROR_FORMAT, err.Format()));
+ }
+
+ return jInfo;
+}
+
+chip::app::DefaultICDClientStorage * getICDClientStorage()
+{
+ return &sICDClientStorage;
+}
diff --git a/src/controller/java/AndroidICDClient.h b/src/controller/java/AndroidICDClient.h
new file mode 100644
index 0000000..e5b929e
--- /dev/null
+++ b/src/controller/java/AndroidICDClient.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @file
+ * Implementation of ICD Client API for Android Platform
+ *
+ */
+
+#pragma once
+
+#include <app/icd/client/DefaultICDClientStorage.h>
+#include <lib/support/JniReferences.h>
+
+jobject getICDClientInfo(JNIEnv * env, const char * icdClientInfoSign, jint jFabricIndex);
+
+chip::app::DefaultICDClientStorage * getICDClientStorage();
diff --git a/src/controller/java/AndroidInteractionClient.cpp b/src/controller/java/AndroidInteractionClient.cpp
index 6ab01bc..84506fd 100644
--- a/src/controller/java/AndroidInteractionClient.cpp
+++ b/src/controller/java/AndroidInteractionClient.cpp
@@ -46,7 +46,7 @@
CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList,
jobject eventPathList, jobject dataVersionFilterList, jint minInterval, jint maxInterval,
- jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin)
+ jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin, jboolean isPeerLIT)
{
chip::DeviceLayer::StackLock lock;
CHIP_ERROR err = CHIP_NO_ERROR;
@@ -128,6 +128,9 @@
params.mEventNumber.SetValue(static_cast<chip::EventNumber>(JniReferences::GetInstance().LongToPrimitive(eventMin)));
}
+ params.mIsPeerLIT = (isPeerLIT == JNI_TRUE);
+ ChipLogProgress(Controller, "Peer ICD type is set to %s", params.mIsPeerLIT ? "LIT-ICD" : "non LIT-ICD");
+
if (eventPathList != nullptr)
{
jint jNumEventPaths = 0;
@@ -804,6 +807,30 @@
return err;
}
+jlong getRemoteDeviceId(jlong devicePtr)
+{
+ OperationalDeviceProxy * chipDevice = reinterpret_cast<OperationalDeviceProxy *>(devicePtr);
+ if (chipDevice == nullptr)
+ {
+ ChipLogProgress(Controller, "Could not cast device pointer to Device object");
+ return static_cast<jlong>(chip::kUndefinedNodeId);
+ }
+
+ return static_cast<jlong>(chipDevice->GetDeviceId());
+}
+
+jint getFabricIndex(jlong devicePtr)
+{
+ OperationalDeviceProxy * chipDevice = reinterpret_cast<OperationalDeviceProxy *>(devicePtr);
+ if (chipDevice == nullptr)
+ {
+ ChipLogProgress(Controller, "Could not cast device pointer to Device object");
+ return static_cast<jint>(chip::kUndefinedFabricIndex);
+ }
+
+ return static_cast<jint>(chipDevice->GetPeerScopedNodeId().GetFabricIndex());
+}
+
/**
* Takes objects in attributePathList, converts them to app:AttributePathParams, and appends them to outAttributePathParamsList.
*/
diff --git a/src/controller/java/AndroidInteractionClient.h b/src/controller/java/AndroidInteractionClient.h
index 32ee629..646ac14 100644
--- a/src/controller/java/AndroidInteractionClient.h
+++ b/src/controller/java/AndroidInteractionClient.h
@@ -22,7 +22,7 @@
CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList,
jobject eventPathList, jobject dataVersionFilterList, jint minInterval, jint maxInterval,
- jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin);
+ jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin, jboolean isPeerLIT);
CHIP_ERROR read(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList,
jobject dataVersionFilterList, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin);
CHIP_ERROR write(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributeList,
@@ -32,3 +32,6 @@
CHIP_ERROR extendableInvoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject invokeElementList,
jint timedRequestTimeoutMs, jint imTimeoutMs);
CHIP_ERROR shutdownSubscriptions(JNIEnv * env, jlong handle, jobject fabricIndex, jobject peerNodeId, jobject subscriptionId);
+
+jlong getRemoteDeviceId(jlong devicePtr);
+jint getFabricIndex(jlong devicePtr);
diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn
index 129ebe6..e22c50c 100644
--- a/src/controller/java/BUILD.gn
+++ b/src/controller/java/BUILD.gn
@@ -51,11 +51,14 @@
"AndroidConnectionFailureExceptions.h",
"AndroidControllerExceptions.cpp",
"AndroidControllerExceptions.h",
+ "AndroidICDClient.cpp",
+ "AndroidICDClient.h",
"AndroidInteractionClient.cpp",
"AndroidInteractionClient.h",
"BaseCHIPCluster-JNI.cpp",
"CHIPAttributeTLVValueDecoder.h",
"CHIPEventTLVValueDecoder.h",
+ "CHIPICDClient-JNI.cpp",
"CHIPInteractionClient-JNI.cpp",
"CHIPInteractionClient-JNI.h",
]
@@ -70,6 +73,7 @@
}
deps = [
+ "${chip_root}/src/app/icd/client:manager",
"${chip_root}/src/lib",
"${chip_root}/src/lib/support/jsontlv",
"${chip_root}/src/platform",
@@ -136,6 +140,7 @@
"DeviceAttestationDelegateBridge.h",
"GroupDeviceProxy.h",
"MatterCallbacks-JNI.cpp",
+ "MatterICDClient-JNI.cpp",
"MatterInteractionClient-JNI.cpp",
]
@@ -431,12 +436,14 @@
sources = [
"src/matter/controller/CompletionListenerAdapter.kt",
"src/matter/controller/ControllerParams.kt",
+ "src/matter/controller/ICDClientInfo.kt",
"src/matter/controller/InteractionClient.kt",
"src/matter/controller/InvokeCallback.kt",
"src/matter/controller/InvokeCallbackJni.kt",
"src/matter/controller/MatterController.kt",
"src/matter/controller/MatterControllerException.kt",
"src/matter/controller/MatterControllerImpl.kt",
+ "src/matter/controller/MatterICDClientImpl.kt",
"src/matter/controller/Messages.kt",
"src/matter/controller/OperationalKeyConfig.kt",
"src/matter/controller/ReportCallback.kt",
@@ -499,10 +506,12 @@
sources = [
"src/chip/devicecontroller/ChipClusterException.java",
"src/chip/devicecontroller/ChipDeviceControllerException.java",
+ "src/chip/devicecontroller/ChipICDClient.java",
"src/chip/devicecontroller/ChipInteractionClient.java",
"src/chip/devicecontroller/ExtendableInvokeCallback.java",
"src/chip/devicecontroller/ExtendableInvokeCallbackJni.java",
"src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java",
+ "src/chip/devicecontroller/ICDClientInfo.java",
"src/chip/devicecontroller/InvokeCallback.java",
"src/chip/devicecontroller/InvokeCallbackJni.java",
"src/chip/devicecontroller/ReportCallback.java",
@@ -600,7 +609,6 @@
"src/chip/devicecontroller/GroupKeySecurityPolicy.java",
"src/chip/devicecontroller/ICDCheckInDelegate.java",
"src/chip/devicecontroller/ICDCheckInDelegateWrapper.java",
- "src/chip/devicecontroller/ICDClientInfo.java",
"src/chip/devicecontroller/ICDDeviceInfo.java",
"src/chip/devicecontroller/ICDRegistrationInfo.java",
"src/chip/devicecontroller/KeypairDelegate.java",
diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp
index dd034ca..9b3d10a 100644
--- a/src/controller/java/CHIPDeviceController-JNI.cpp
+++ b/src/controller/java/CHIPDeviceController-JNI.cpp
@@ -2154,73 +2154,6 @@
return javaCsr;
}
-JNI_METHOD(jobject, getICDClientInfo)(JNIEnv * env, jobject self, jlong handle, jint jFabricIndex)
-{
- chip::DeviceLayer::StackLock lock;
-
- CHIP_ERROR err = CHIP_NO_ERROR;
-
- jobject jInfo = nullptr;
- chip::app::ICDClientInfo info;
- chip::FabricIndex fabricIndex = static_cast<chip::FabricIndex>(jFabricIndex);
-
- ChipLogProgress(Controller, "getICDClientInfo(%u) called", fabricIndex);
- AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle);
- VerifyOrReturnValue(wrapper != nullptr, nullptr, ChipLogError(Controller, "wrapper is null"));
-
- err = JniReferences::GetInstance().CreateArrayList(jInfo);
- VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
- ChipLogError(Controller, "CreateArrayList failed!: %" CHIP_ERROR_FORMAT, err.Format()));
-
- auto iter = wrapper->getICDClientStorage()->IterateICDClientInfo();
- VerifyOrReturnValue(iter != nullptr, nullptr, ChipLogError(Controller, "IterateICDClientInfo failed!"));
- app::DefaultICDClientStorage::ICDClientInfoIteratorWrapper clientInfoIteratorWrapper(iter);
-
- jmethodID constructor;
- jclass infoClass;
- JniLocalReferenceScope scope(env);
-
- err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/ICDClientInfo", infoClass);
- VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
- ChipLogError(Controller, "Find ICDClientInfo class: %" CHIP_ERROR_FORMAT, err.Format()));
-
- env->ExceptionClear();
- constructor = env->GetMethodID(infoClass, "<init>", "(JJJJ[B[B)V");
- VerifyOrReturnValue(constructor != nullptr, nullptr, ChipLogError(Controller, "Find GetMethodID error!"));
-
- while (iter->Next(info))
- {
- jbyteArray jIcdAesKey = nullptr;
- jbyteArray jIcdHmacKey = nullptr;
- jobject jICDClientInfo = nullptr;
-
- if (info.peer_node.GetFabricIndex() != fabricIndex)
- {
- continue;
- }
-
- err = chip::JniReferences::GetInstance().N2J_ByteArray(env, info.aes_key_handle.As<Crypto::Symmetric128BitsKeyByteArray>(),
- CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, jIcdAesKey);
- VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
- ChipLogError(Controller, "ICD AES KEY N2J_ByteArray error!: %" CHIP_ERROR_FORMAT, err.Format()));
-
- err = chip::JniReferences::GetInstance().N2J_ByteArray(env, info.hmac_key_handle.As<Crypto::Symmetric128BitsKeyByteArray>(),
- CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, jIcdHmacKey);
- VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
- ChipLogError(Controller, "ICD HMAC KEY N2J_ByteArray error!: %" CHIP_ERROR_FORMAT, err.Format()));
-
- jICDClientInfo = (jobject) env->NewObject(infoClass, constructor, static_cast<jlong>(info.peer_node.GetNodeId()),
- static_cast<jlong>(info.start_icd_counter), static_cast<jlong>(info.offset),
- static_cast<jlong>(info.monitored_subject), jIcdAesKey, jIcdHmacKey);
-
- err = JniReferences::GetInstance().AddToList(jInfo, jICDClientInfo);
- VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
- ChipLogError(Controller, "AddToList error!: %" CHIP_ERROR_FORMAT, err.Format()));
- }
-
- return jInfo;
-}
-
void * IOThreadMain(void * arg)
{
JNIEnv * env;
diff --git a/src/controller/java/CHIPICDClient-JNI.cpp b/src/controller/java/CHIPICDClient-JNI.cpp
new file mode 100644
index 0000000..b1fb257
--- /dev/null
+++ b/src/controller/java/CHIPICDClient-JNI.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * 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 "AndroidICDClient.h"
+
+#include <platform/PlatformManager.h>
+
+#define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_chip_devicecontroller_ChipICDClient_##METHOD_NAME
+
+JNI_METHOD(jobject, getICDClientInfo)(JNIEnv * env, jobject self, jint jFabricIndex)
+{
+ chip::DeviceLayer::StackLock lock;
+
+ return getICDClientInfo(env, "chip/devicecontroller/ICDClientInfo", jFabricIndex);
+}
diff --git a/src/controller/java/CHIPInteractionClient-JNI.cpp b/src/controller/java/CHIPInteractionClient-JNI.cpp
index 62abf35..f6d8e0a 100644
--- a/src/controller/java/CHIPInteractionClient-JNI.cpp
+++ b/src/controller/java/CHIPInteractionClient-JNI.cpp
@@ -73,10 +73,10 @@
JNI_METHOD(void, subscribe)
(JNIEnv * env, jobject self, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList,
jobject dataVersionFilterList, jint minInterval, jint maxInterval, jboolean keepSubscriptions, jboolean isFabricFiltered,
- jint imTimeoutMs, jobject eventMin)
+ jint imTimeoutMs, jobject eventMin, jboolean isPeerLIT)
{
CHIP_ERROR err = subscribe(env, handle, callbackHandle, devicePtr, attributePathList, eventPathList, dataVersionFilterList,
- minInterval, maxInterval, keepSubscriptions, isFabricFiltered, imTimeoutMs, eventMin);
+ minInterval, maxInterval, keepSubscriptions, isFabricFiltered, imTimeoutMs, eventMin, isPeerLIT);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "JNI IM Subscribe Error: %" CHIP_ERROR_FORMAT, err.Format());
@@ -138,3 +138,15 @@
ChipLogError(Controller, "Failed to shutdown subscriptions with Error: %" CHIP_ERROR_FORMAT, err.Format());
}
}
+
+JNI_METHOD(jlong, getRemoteDeviceId)
+(JNIEnv * env, jobject self, jlong devicePtr)
+{
+ return getRemoteDeviceId(devicePtr);
+}
+
+JNI_METHOD(jint, getFabricIndex)
+(JNIEnv * env, jobject self, jlong devicePtr)
+{
+ return getFabricIndex(devicePtr);
+}
diff --git a/src/controller/java/MatterICDClient-JNI.cpp b/src/controller/java/MatterICDClient-JNI.cpp
new file mode 100644
index 0000000..45ed4d9
--- /dev/null
+++ b/src/controller/java/MatterICDClient-JNI.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * 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 "AndroidICDClient.h"
+
+#include <platform/PlatformManager.h>
+
+#define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_matter_controller_MatterICDClientImpl_##METHOD_NAME
+
+JNI_METHOD(jobject, getICDClientInfo)(JNIEnv * env, jobject self, jint jFabricIndex)
+{
+ chip::DeviceLayer::StackLock lock;
+
+ return getICDClientInfo(env, "matter/controller/ICDClientInfo", jFabricIndex);
+}
diff --git a/src/controller/java/MatterInteractionClient-JNI.cpp b/src/controller/java/MatterInteractionClient-JNI.cpp
index 152e52a..5b526a3 100644
--- a/src/controller/java/MatterInteractionClient-JNI.cpp
+++ b/src/controller/java/MatterInteractionClient-JNI.cpp
@@ -22,10 +22,10 @@
JNI_METHOD(void, subscribe)
(JNIEnv * env, jobject self, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList,
- jint minInterval, jint maxInterval, jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs)
+ jint minInterval, jint maxInterval, jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jboolean isPeerLIT)
{
CHIP_ERROR err = subscribe(env, handle, callbackHandle, devicePtr, attributePathList, eventPathList, nullptr, minInterval,
- maxInterval, keepSubscriptions, isFabricFiltered, imTimeoutMs, nullptr);
+ maxInterval, keepSubscriptions, isFabricFiltered, imTimeoutMs, nullptr, isPeerLIT);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "JNI IM Subscribe Error: %" CHIP_ERROR_FORMAT, err.Format());
@@ -77,3 +77,15 @@
ChipLogError(Controller, "JNI IM Batch Invoke Error: %" CHIP_ERROR_FORMAT, err.Format());
}
}
+
+JNI_METHOD(jlong, getRemoteDeviceId)
+(JNIEnv * env, jobject self, jlong devicePtr)
+{
+ return getRemoteDeviceId(devicePtr);
+}
+
+JNI_METHOD(jint, getFabricIndex)
+(JNIEnv * env, jobject self, jlong devicePtr)
+{
+ return getFabricIndex(devicePtr);
+}
diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
index 0844ffe..2e64d37 100644
--- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
+++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
@@ -142,7 +142,9 @@
int maxInterval) {
ReportCallbackJni jniCallback = new ReportCallbackJni(callback, callback, callback);
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, attributeId);
- ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null);
+ int fabricIndex = ChipInteractionClient.getFabricIndex(devicePtr);
+ long deviceId = ChipInteractionClient.getRemoteDeviceId(devicePtr);
+ ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null, ChipICDClient.isPeerICDClient(fabricIndex, deviceId));
}
protected void invoke(
diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java
index 482bc2e..653cebf 100644
--- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java
+++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java
@@ -743,7 +743,7 @@
}
public List<ICDClientInfo> getICDClientInfo() {
- return getICDClientInfo(deviceControllerPtr, getFabricIndex(deviceControllerPtr));
+ return getICDClientInfo(getFabricIndex(deviceControllerPtr));
}
/**
@@ -752,7 +752,7 @@
* @param fabricIndex the fabric index to check
*/
public List<ICDClientInfo> getICDClientInfo(int fabricIndex) {
- return getICDClientInfo(deviceControllerPtr, fabricIndex);
+ return ChipICDClient.getICDClientInfo(fabricIndex);
}
/* Shuts down all active subscriptions. */
@@ -838,7 +838,10 @@
false,
false,
imTimeoutMs,
- null);
+ null,
+ ChipICDClient.isPeerICDClient(
+ ChipInteractionClient.getFabricIndex(devicePtr),
+ ChipInteractionClient.getRemoteDeviceId(devicePtr)));
}
/**
@@ -876,7 +879,10 @@
false,
false,
imTimeoutMs,
- null);
+ null,
+ ChipICDClient.isPeerICDClient(
+ ChipInteractionClient.getFabricIndex(devicePtr),
+ ChipInteractionClient.getRemoteDeviceId(devicePtr)));
}
public void subscribeToEventPath(
@@ -902,7 +908,10 @@
false,
false,
imTimeoutMs,
- eventMin);
+ eventMin,
+ ChipICDClient.isPeerICDClient(
+ ChipInteractionClient.getFabricIndex(devicePtr),
+ ChipInteractionClient.getRemoteDeviceId(devicePtr)));
}
/**
@@ -936,7 +945,10 @@
keepSubscriptions,
isFabricFiltered,
imTimeoutMs,
- null);
+ null,
+ ChipICDClient.isPeerICDClient(
+ ChipInteractionClient.getFabricIndex(devicePtr),
+ ChipInteractionClient.getRemoteDeviceId(devicePtr)));
}
/**
@@ -988,7 +1000,10 @@
keepSubscriptions,
isFabricFiltered,
imTimeoutMs,
- null);
+ null,
+ ChipICDClient.isPeerICDClient(
+ ChipInteractionClient.getFabricIndex(devicePtr),
+ ChipInteractionClient.getRemoteDeviceId(devicePtr)));
}
public void subscribeToPath(
@@ -1019,7 +1034,47 @@
keepSubscriptions,
isFabricFiltered,
imTimeoutMs,
- eventMin);
+ eventMin,
+ ChipICDClient.isPeerICDClient(
+ ChipInteractionClient.getFabricIndex(devicePtr),
+ ChipInteractionClient.getRemoteDeviceId(devicePtr)));
+ }
+
+ public void subscribeToPath(
+ SubscriptionEstablishedCallback subscriptionEstablishedCallback,
+ ResubscriptionAttemptCallback resubscriptionAttemptCallback,
+ ReportCallback reportCallback,
+ long devicePtr,
+ List<ChipAttributePath> attributePaths,
+ List<ChipEventPath> eventPaths,
+ int minInterval,
+ int maxInterval,
+ boolean keepSubscriptions,
+ boolean isFabricFiltered,
+ int imTimeoutMs,
+ @Nullable Long eventMin,
+ @Nullable Boolean isPeerLIT) {
+ ReportCallbackJni jniCallback =
+ new ReportCallbackJni(
+ subscriptionEstablishedCallback, reportCallback, resubscriptionAttemptCallback);
+ ChipInteractionClient.subscribe(
+ deviceControllerPtr,
+ jniCallback.getCallbackHandle(),
+ devicePtr,
+ attributePaths,
+ eventPaths,
+ null,
+ minInterval,
+ maxInterval,
+ keepSubscriptions,
+ isFabricFiltered,
+ imTimeoutMs,
+ eventMin,
+ isPeerLIT != null
+ ? isPeerLIT
+ : ChipICDClient.isPeerICDClient(
+ ChipInteractionClient.getFabricIndex(devicePtr),
+ ChipInteractionClient.getRemoteDeviceId(devicePtr)));
}
/**
@@ -1526,8 +1581,6 @@
private native void updateCommissioningICDRegistrationInfo(
long deviceControllerPtr, ICDRegistrationInfo icdRegistrationInfo);
- private native List<ICDClientInfo> getICDClientInfo(long deviceControllerPtr, long fabricIndex);
-
private native long onNOCChainGeneration(long deviceControllerPtr, ControllerParams params);
private native int getFabricIndex(long deviceControllerPtr);
diff --git a/src/controller/java/src/chip/devicecontroller/ChipICDClient.java b/src/controller/java/src/chip/devicecontroller/ChipICDClient.java
new file mode 100644
index 0000000..4d95a09
--- /dev/null
+++ b/src/controller/java/src/chip/devicecontroller/ChipICDClient.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+package chip.devicecontroller;
+
+import java.util.List;
+
+public class ChipICDClient {
+ public static boolean isPeerICDClient(int fabricIndex, long deviceId) {
+ List<ICDClientInfo> clientInfo = getICDClientInfo(fabricIndex);
+ if (clientInfo == null) {
+ return false;
+ }
+
+ return clientInfo.stream().anyMatch(info -> info.getPeerNodeId() == deviceId);
+ }
+
+ public static native List<ICDClientInfo> getICDClientInfo(int fabricIndex);
+}
diff --git a/src/controller/java/src/chip/devicecontroller/ChipInteractionClient.java b/src/controller/java/src/chip/devicecontroller/ChipInteractionClient.java
index d06f117..a20d1ce 100644
--- a/src/controller/java/src/chip/devicecontroller/ChipInteractionClient.java
+++ b/src/controller/java/src/chip/devicecontroller/ChipInteractionClient.java
@@ -37,7 +37,8 @@
boolean keepSubscriptions,
boolean isFabricFiltered,
int imTimeoutMs,
- @Nullable Long eventMin);
+ @Nullable Long eventMin,
+ boolean isPeerICD);
static native void read(
long deviceControllerPtr,
@@ -79,4 +80,8 @@
@Nullable Integer fabricIndex,
@Nullable Long peerNodeId,
@Nullable Long subscriptionId);
+
+ static native long getRemoteDeviceId(long devicePtr);
+
+ static native int getFabricIndex(long devicePtr);
}
diff --git a/src/controller/java/src/matter/controller/ICDClientInfo.kt b/src/controller/java/src/matter/controller/ICDClientInfo.kt
new file mode 100644
index 0000000..3f0f302
--- /dev/null
+++ b/src/controller/java/src/matter/controller/ICDClientInfo.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+package matter.controller
+
+/** Class for holding ICD Client information. */
+data class ICDClientInfo(
+ val peerNodeId: Long,
+ val startCounter: Long,
+ val offset: Long,
+ val monitoredSubject: Long,
+ val icdAesKey: ByteArray,
+ val icdHmacKey: ByteArray
+) {
+ override fun toString(): String = "$peerNodeId/$startCounter/$offset/$monitoredSubject"
+}
diff --git a/src/controller/java/src/matter/controller/MatterControllerImpl.kt b/src/controller/java/src/matter/controller/MatterControllerImpl.kt
index dde29ee..1004b64 100644
--- a/src/controller/java/src/matter/controller/MatterControllerImpl.kt
+++ b/src/controller/java/src/matter/controller/MatterControllerImpl.kt
@@ -204,6 +204,9 @@
reportHandler,
resubscriptionAttemptHandler
)
+
+ val fabricIndex = getFabricIndex(devicePtr)
+ val deviceId = getRemoteDeviceId(devicePtr)
subscribe(
deviceControllerPtr,
reportCallbackJni.getJniHandle(),
@@ -214,7 +217,8 @@
request.maxInterval.seconds.toInt(),
request.keepSubscriptions,
request.fabricFiltered,
- CHIP_IM_TIMEOUT_MS
+ CHIP_IM_TIMEOUT_MS,
+ MatterICDClientImpl.isPeerICDClient(fabricIndex, deviceId)
)
awaitClose { logger.log(Level.FINE, "Closing flow") }
@@ -232,7 +236,8 @@
maxInterval: Int,
keepSubscriptions: Boolean,
isFabricFiltered: Boolean,
- imTimeoutMs: Int
+ imTimeoutMs: Int,
+ isPeerLIT: Boolean
)
override suspend fun read(request: ReadRequest): ReadResponse {
@@ -450,6 +455,10 @@
imTimeoutMs: Int
)
+ external fun getRemoteDeviceId(devicePtr: Long): Long
+
+ external fun getFabricIndex(devicePtr: Long): Int
+
override fun close() {
logger.log(Level.INFO, "MatterController is closed")
deviceController.shutdownCommissioning()
@@ -477,65 +486,6 @@
}
}
- // private fun ChipAttributePath.wrap(): AttributePath {
- // return AttributePath(
- // endpointId.getId().toUShort(),
- // clusterId.getId().toUInt(),
- // attributeId.getId().toUInt()
- // )
- // }
-
- // private fun ChipEventPath.wrap(): EventPath {
- // return EventPath(
- // endpointId.getId().toUShort(),
- // clusterId.getId().toUInt(),
- // eventId.getId().toUInt()
- // )
- // }
-
- // private fun chip.devicecontroller.model.NodeState.wrap(): NodeState {
- // return NodeState(
- // endpoints = endpointStates.mapValues { (id, value) -> value.wrap(id) }.toMutableMap(),
- // )
- // }
-
- // private fun chip.devicecontroller.model.EndpointState.wrap(id: Int): EndpointState {
- // return EndpointState(
- // id,
- // clusterStates.mapValues { (id, value) -> value.wrap(id) }.toMutableMap()
- // )
- // }
-
- // private fun chip.devicecontroller.model.ClusterState.wrap(id: Long): ClusterState {
- // return ClusterState(
- // id,
- // attributeStates.mapValues { (id, value) -> value.wrap(id) }.toMutableMap(),
- // eventStates
- // .mapValues { (id, value) ->
- // value.map { eventState -> eventState.wrap(id) }.toMutableList()
- // }
- // .toMutableMap()
- // )
- // }
-
- // private fun chip.devicecontroller.model.AttributeState.wrap(id: Long): AttributeState {
- // return AttributeState(id, tlv, json.toString(), AttributePath(0U, 0U, id.toUInt()), value)
- // }
-
- // private fun chip.devicecontroller.model.EventState.wrap(id: Long): EventState {
- // return EventState(
- // id,
- // eventNumber,
- // priorityLevel,
- // timestampType,
- // timestampValue,
- // tlv,
- // EventPath(0U, 0U, id.toUInt()),
- // json.toString(),
- // value
- // )
- // }
-
init {
val config: OperationalKeyConfig? = params.operationalKeyConfig
val paramsBuilder =
diff --git a/src/controller/java/src/matter/controller/MatterICDClientImpl.kt b/src/controller/java/src/matter/controller/MatterICDClientImpl.kt
new file mode 100644
index 0000000..ae91e34
--- /dev/null
+++ b/src/controller/java/src/matter/controller/MatterICDClientImpl.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2024 Project CHIP Authors
+ * All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+package matter.controller
+
+object MatterICDClientImpl {
+ fun isPeerICDClient(fabricIndex: Int, deviceId: Long): Boolean {
+ val clientInfo = getICDClientInfo(fabricIndex) ?: return false
+ return clientInfo.firstOrNull { it.peerNodeId == deviceId } != null
+ }
+
+ external fun getICDClientInfo(fabricIndex: Int): List<ICDClientInfo>?
+}