Skip to content

Commit 6cdb5da

Browse files
[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>
1 parent 7bd2409 commit 6cdb5da

21 files changed

+449
-160
lines changed

scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja

+3-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ public class ChipClusters {
219219
int maxInterval) {
220220
ReportCallbackJni jniCallback = new ReportCallbackJni(callback, callback, callback);
221221
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, attributeId);
222-
ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null);
222+
int fabricIndex = ChipInteractionClient.getFabricIndex(devicePtr);
223+
long deviceId = ChipInteractionClient.getRemoteDeviceId(devicePtr);
224+
ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null, ChipICDClient.isPeerICDClient(fabricIndex, deviceId));
223225
}
224226

225227
protected void invoke(

scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ protected void subscribeAttribute(
142142
int maxInterval) {
143143
ReportCallbackJni jniCallback = new ReportCallbackJni(callback, callback, callback);
144144
ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, attributeId);
145-
ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null);
145+
int fabricIndex = ChipInteractionClient.getFabricIndex(devicePtr);
146+
long deviceId = ChipInteractionClient.getRemoteDeviceId(devicePtr);
147+
ChipInteractionClient.subscribe(0, jniCallback.getCallbackHandle(), devicePtr, Arrays.asList(path), null, null, minInterval, maxInterval, false, true, timeoutMillis.orElse(0L).intValue(), null, ChipICDClient.isPeerICDClient(fabricIndex, deviceId));
146148
}
147149

148150
protected void invoke(

src/controller/java/AndroidDeviceControllerWrapper.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <lib/support/JniTypeWrappers.h>
3131

3232
#include <controller/CHIPDeviceControllerFactory.h>
33+
#include <controller/java/AndroidICDClient.h>
3334
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
3435
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
3536
#include <lib/core/TLV.h>
@@ -185,7 +186,7 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
185186
chip::Credentials::SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));
186187
}
187188

188-
*errInfoOnFailure = wrapper->mICDClientStorage.Init(wrapperStorage, &wrapper->mSessionKeystore);
189+
*errInfoOnFailure = getICDClientStorage()->Init(wrapperStorage, &wrapper->mSessionKeystore);
189190
if (*errInfoOnFailure != CHIP_NO_ERROR)
190191
{
191192
ChipLogError(Controller, "ICD Client Storage failure");
@@ -401,12 +402,12 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
401402
*errInfoOnFailure = chip::Credentials::SetSingleIpkEpochKey(
402403
&wrapper->mGroupDataProvider, wrapper->Controller()->GetFabricIndex(), ipkSpan, compressedFabricIdSpan);
403404

404-
wrapper->getICDClientStorage()->UpdateFabricList(wrapper->Controller()->GetFabricIndex());
405+
getICDClientStorage()->UpdateFabricList(wrapper->Controller()->GetFabricIndex());
405406

406407
auto engine = chip::app::InteractionModelEngine::GetInstance();
407-
*errInfoOnFailure = wrapper->mCheckInDelegate.Init(&wrapper->mICDClientStorage, engine);
408+
*errInfoOnFailure = wrapper->mCheckInDelegate.Init(getICDClientStorage(), engine);
408409
*errInfoOnFailure = wrapper->mCheckInHandler.Init(DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(),
409-
&wrapper->mICDClientStorage, &wrapper->mCheckInDelegate, engine);
410+
getICDClientStorage(), &wrapper->mCheckInDelegate, engine);
410411

411412
memset(ipkBuffer.data(), 0, ipkBuffer.size());
412413

@@ -725,7 +726,7 @@ void AndroidDeviceControllerWrapper::OnCommissioningComplete(NodeId deviceId, CH
725726

726727
if (error != CHIP_NO_ERROR && mDeviceIsICD)
727728
{
728-
CHIP_ERROR deleteEntryError = mICDClientStorage.DeleteEntry(ScopedNodeId(deviceId, Controller()->GetFabricIndex()));
729+
CHIP_ERROR deleteEntryError = getICDClientStorage()->DeleteEntry(ScopedNodeId(deviceId, Controller()->GetFabricIndex()));
729730
if (deleteEntryError != CHIP_NO_ERROR)
730731
{
731732
ChipLogError(chipTool, "Failed to delete ICD entry: %" CHIP_ERROR_FORMAT, deleteEntryError.Format());
@@ -1003,10 +1004,10 @@ void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdN
10031004

10041005
ByteSpan symmetricKey = mAutoCommissioner.GetCommissioningParameters().GetICDSymmetricKey().Value();
10051006

1006-
err = mICDClientStorage.SetKey(clientInfo, symmetricKey);
1007+
err = getICDClientStorage()->SetKey(clientInfo, symmetricKey);
10071008
if (err == CHIP_NO_ERROR)
10081009
{
1009-
err = mICDClientStorage.StoreEntry(clientInfo);
1010+
err = getICDClientStorage()->StoreEntry(clientInfo);
10101011
}
10111012

10121013
if (err == CHIP_NO_ERROR)
@@ -1015,7 +1016,7 @@ void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdN
10151016
}
10161017
else
10171018
{
1018-
mICDClientStorage.RemoveKey(clientInfo);
1019+
getICDClientStorage()->RemoveKey(clientInfo);
10191020
ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(icdNodeId),
10201021
err.AsString());
10211022
}

src/controller/java/AndroidDeviceControllerWrapper.h

-3
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
212212

213213
CHIP_ERROR FinishOTAProvider();
214214

215-
chip::app::DefaultICDClientStorage * getICDClientStorage() { return &mICDClientStorage; }
216-
217215
CHIP_ERROR SetICDCheckInDelegate(jobject checkInDelegate);
218216

219217
private:
@@ -228,7 +226,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
228226
// TODO: This may need to be injected as a SessionKeystore*
229227
chip::Crypto::RawKeySessionKeystore mSessionKeystore;
230228

231-
chip::app::DefaultICDClientStorage mICDClientStorage;
232229
chip::app::AndroidCheckInDelegate mCheckInDelegate;
233230
chip::app::CheckInHandler mCheckInHandler;
234231

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
/**
20+
* @file
21+
* Implementation of ICD Client API for Android Platform
22+
*
23+
*/
24+
25+
#include "AndroidICDClient.h"
26+
27+
#include <app/icd/client/ICDClientInfo.h>
28+
29+
chip::app::DefaultICDClientStorage sICDClientStorage;
30+
31+
jobject getICDClientInfo(JNIEnv * env, const char * icdClientInfoSign, jint jFabricIndex)
32+
{
33+
CHIP_ERROR err = CHIP_NO_ERROR;
34+
35+
jobject jInfo = nullptr;
36+
chip::app::ICDClientInfo info;
37+
chip::FabricIndex fabricIndex = static_cast<chip::FabricIndex>(jFabricIndex);
38+
39+
ChipLogProgress(Controller, "getICDClientInfo(%u) called", fabricIndex);
40+
41+
err = chip::JniReferences::GetInstance().CreateArrayList(jInfo);
42+
VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
43+
ChipLogError(Controller, "CreateArrayList failed!: %" CHIP_ERROR_FORMAT, err.Format()));
44+
45+
auto iter = getICDClientStorage()->IterateICDClientInfo();
46+
VerifyOrReturnValue(iter != nullptr, nullptr, ChipLogError(Controller, "IterateICDClientInfo failed!"));
47+
chip::app::DefaultICDClientStorage::ICDClientInfoIteratorWrapper clientInfoIteratorWrapper(iter);
48+
49+
jmethodID constructor;
50+
jclass infoClass;
51+
chip::JniLocalReferenceScope scope(env);
52+
53+
err = chip::JniReferences::GetInstance().GetLocalClassRef(env, icdClientInfoSign, infoClass);
54+
VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
55+
ChipLogError(Controller, "Find ICDClientInfo class: %" CHIP_ERROR_FORMAT, err.Format()));
56+
57+
env->ExceptionClear();
58+
constructor = env->GetMethodID(infoClass, "<init>", "(JJJJ[B[B)V");
59+
VerifyOrReturnValue(constructor != nullptr, nullptr, ChipLogError(Controller, "Find GetMethodID error!"));
60+
61+
while (iter->Next(info))
62+
{
63+
jbyteArray jIcdAesKey = nullptr;
64+
jbyteArray jIcdHmacKey = nullptr;
65+
jobject jICDClientInfo = nullptr;
66+
67+
if (info.peer_node.GetFabricIndex() != fabricIndex)
68+
{
69+
continue;
70+
}
71+
72+
err = chip::JniReferences::GetInstance().N2J_ByteArray(env,
73+
info.aes_key_handle.As<chip::Crypto::Symmetric128BitsKeyByteArray>(),
74+
chip::Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, jIcdAesKey);
75+
VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
76+
ChipLogError(Controller, "ICD AES KEY N2J_ByteArray error!: %" CHIP_ERROR_FORMAT, err.Format()));
77+
78+
err = chip::JniReferences::GetInstance().N2J_ByteArray(
79+
env, info.hmac_key_handle.As<chip::Crypto::Symmetric128BitsKeyByteArray>(),
80+
chip::Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, jIcdHmacKey);
81+
VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
82+
ChipLogError(Controller, "ICD HMAC KEY N2J_ByteArray error!: %" CHIP_ERROR_FORMAT, err.Format()));
83+
84+
jICDClientInfo = (jobject) env->NewObject(infoClass, constructor, static_cast<jlong>(info.peer_node.GetNodeId()),
85+
static_cast<jlong>(info.start_icd_counter), static_cast<jlong>(info.offset),
86+
static_cast<jlong>(info.monitored_subject), jIcdAesKey, jIcdHmacKey);
87+
88+
err = chip::JniReferences::GetInstance().AddToList(jInfo, jICDClientInfo);
89+
VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
90+
ChipLogError(Controller, "AddToList error!: %" CHIP_ERROR_FORMAT, err.Format()));
91+
}
92+
93+
return jInfo;
94+
}
95+
96+
chip::app::DefaultICDClientStorage * getICDClientStorage()
97+
{
98+
return &sICDClientStorage;
99+
}
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
/**
20+
* @file
21+
* Implementation of ICD Client API for Android Platform
22+
*
23+
*/
24+
25+
#pragma once
26+
27+
#include <app/icd/client/DefaultICDClientStorage.h>
28+
#include <lib/support/JniReferences.h>
29+
30+
jobject getICDClientInfo(JNIEnv * env, const char * icdClientInfoSign, jint jFabricIndex);
31+
32+
chip::app::DefaultICDClientStorage * getICDClientStorage();

src/controller/java/AndroidInteractionClient.cpp

+28-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static CHIP_ERROR ParseDataVersionFilterList(jobject dataVersionFilterList,
4646

4747
CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList,
4848
jobject eventPathList, jobject dataVersionFilterList, jint minInterval, jint maxInterval,
49-
jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin)
49+
jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin, jboolean isPeerLIT)
5050
{
5151
chip::DeviceLayer::StackLock lock;
5252
CHIP_ERROR err = CHIP_NO_ERROR;
@@ -128,6 +128,9 @@ CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong dev
128128
params.mEventNumber.SetValue(static_cast<chip::EventNumber>(JniReferences::GetInstance().LongToPrimitive(eventMin)));
129129
}
130130

131+
params.mIsPeerLIT = (isPeerLIT == JNI_TRUE);
132+
ChipLogProgress(Controller, "Peer ICD type is set to %s", params.mIsPeerLIT ? "LIT-ICD" : "non LIT-ICD");
133+
131134
if (eventPathList != nullptr)
132135
{
133136
jint jNumEventPaths = 0;
@@ -804,6 +807,30 @@ CHIP_ERROR invoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong device
804807
return err;
805808
}
806809

810+
jlong getRemoteDeviceId(jlong devicePtr)
811+
{
812+
OperationalDeviceProxy * chipDevice = reinterpret_cast<OperationalDeviceProxy *>(devicePtr);
813+
if (chipDevice == nullptr)
814+
{
815+
ChipLogProgress(Controller, "Could not cast device pointer to Device object");
816+
return static_cast<jlong>(chip::kUndefinedNodeId);
817+
}
818+
819+
return static_cast<jlong>(chipDevice->GetDeviceId());
820+
}
821+
822+
jint getFabricIndex(jlong devicePtr)
823+
{
824+
OperationalDeviceProxy * chipDevice = reinterpret_cast<OperationalDeviceProxy *>(devicePtr);
825+
if (chipDevice == nullptr)
826+
{
827+
ChipLogProgress(Controller, "Could not cast device pointer to Device object");
828+
return static_cast<jint>(chip::kUndefinedFabricIndex);
829+
}
830+
831+
return static_cast<jint>(chipDevice->GetPeerScopedNodeId().GetFabricIndex());
832+
}
833+
807834
/**
808835
* Takes objects in attributePathList, converts them to app:AttributePathParams, and appends them to outAttributePathParamsList.
809836
*/

src/controller/java/AndroidInteractionClient.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList,
2424
jobject eventPathList, jobject dataVersionFilterList, jint minInterval, jint maxInterval,
25-
jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin);
25+
jboolean keepSubscriptions, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin, jboolean isPeerLIT);
2626
CHIP_ERROR read(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributePathList, jobject eventPathList,
2727
jobject dataVersionFilterList, jboolean isFabricFiltered, jint imTimeoutMs, jobject eventMin);
2828
CHIP_ERROR write(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject attributeList,
@@ -32,3 +32,6 @@ CHIP_ERROR invoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong device
3232
CHIP_ERROR extendableInvoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong devicePtr, jobject invokeElementList,
3333
jint timedRequestTimeoutMs, jint imTimeoutMs);
3434
CHIP_ERROR shutdownSubscriptions(JNIEnv * env, jlong handle, jobject fabricIndex, jobject peerNodeId, jobject subscriptionId);
35+
36+
jlong getRemoteDeviceId(jlong devicePtr);
37+
jint getFabricIndex(jlong devicePtr);

src/controller/java/BUILD.gn

+9-1
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,14 @@ source_set("android_chip_im_jni") {
5151
"AndroidConnectionFailureExceptions.h",
5252
"AndroidControllerExceptions.cpp",
5353
"AndroidControllerExceptions.h",
54+
"AndroidICDClient.cpp",
55+
"AndroidICDClient.h",
5456
"AndroidInteractionClient.cpp",
5557
"AndroidInteractionClient.h",
5658
"BaseCHIPCluster-JNI.cpp",
5759
"CHIPAttributeTLVValueDecoder.h",
5860
"CHIPEventTLVValueDecoder.h",
61+
"CHIPICDClient-JNI.cpp",
5962
"CHIPInteractionClient-JNI.cpp",
6063
"CHIPInteractionClient-JNI.h",
6164
]
@@ -70,6 +73,7 @@ source_set("android_chip_im_jni") {
7073
}
7174

7275
deps = [
76+
"${chip_root}/src/app/icd/client:manager",
7377
"${chip_root}/src/lib",
7478
"${chip_root}/src/lib/support/jsontlv",
7579
"${chip_root}/src/platform",
@@ -136,6 +140,7 @@ shared_library("jni") {
136140
"DeviceAttestationDelegateBridge.h",
137141
"GroupDeviceProxy.h",
138142
"MatterCallbacks-JNI.cpp",
143+
"MatterICDClient-JNI.cpp",
139144
"MatterInteractionClient-JNI.cpp",
140145
]
141146

@@ -431,12 +436,14 @@ kotlin_library("kotlin_matter_controller") {
431436
sources = [
432437
"src/matter/controller/CompletionListenerAdapter.kt",
433438
"src/matter/controller/ControllerParams.kt",
439+
"src/matter/controller/ICDClientInfo.kt",
434440
"src/matter/controller/InteractionClient.kt",
435441
"src/matter/controller/InvokeCallback.kt",
436442
"src/matter/controller/InvokeCallbackJni.kt",
437443
"src/matter/controller/MatterController.kt",
438444
"src/matter/controller/MatterControllerException.kt",
439445
"src/matter/controller/MatterControllerImpl.kt",
446+
"src/matter/controller/MatterICDClientImpl.kt",
440447
"src/matter/controller/Messages.kt",
441448
"src/matter/controller/OperationalKeyConfig.kt",
442449
"src/matter/controller/ReportCallback.kt",
@@ -499,10 +506,12 @@ android_library("android_chip_im") {
499506
sources = [
500507
"src/chip/devicecontroller/ChipClusterException.java",
501508
"src/chip/devicecontroller/ChipDeviceControllerException.java",
509+
"src/chip/devicecontroller/ChipICDClient.java",
502510
"src/chip/devicecontroller/ChipInteractionClient.java",
503511
"src/chip/devicecontroller/ExtendableInvokeCallback.java",
504512
"src/chip/devicecontroller/ExtendableInvokeCallbackJni.java",
505513
"src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java",
514+
"src/chip/devicecontroller/ICDClientInfo.java",
506515
"src/chip/devicecontroller/InvokeCallback.java",
507516
"src/chip/devicecontroller/InvokeCallbackJni.java",
508517
"src/chip/devicecontroller/ReportCallback.java",
@@ -600,7 +609,6 @@ android_library("java") {
600609
"src/chip/devicecontroller/GroupKeySecurityPolicy.java",
601610
"src/chip/devicecontroller/ICDCheckInDelegate.java",
602611
"src/chip/devicecontroller/ICDCheckInDelegateWrapper.java",
603-
"src/chip/devicecontroller/ICDClientInfo.java",
604612
"src/chip/devicecontroller/ICDDeviceInfo.java",
605613
"src/chip/devicecontroller/ICDRegistrationInfo.java",
606614
"src/chip/devicecontroller/KeypairDelegate.java",

0 commit comments

Comments
 (0)