Skip to content

Commit

Permalink
[Android] Implement LIT ICD for subscription (#33152)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed May 10, 2024
1 parent 5d05c82 commit 9565750
Show file tree
Hide file tree
Showing 21 changed files with 449 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,9 @@ public class ChipClusters {
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ protected void subscribeAttribute(
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(
Expand Down
17 changes: 9 additions & 8 deletions src/controller/java/AndroidDeviceControllerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -185,7 +186,7 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
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");
Expand Down Expand Up @@ -401,12 +402,12 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
*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());

Expand Down Expand Up @@ -725,7 +726,7 @@ void AndroidDeviceControllerWrapper::OnCommissioningComplete(NodeId deviceId, CH

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());
Expand Down Expand Up @@ -1003,10 +1004,10 @@ void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdN

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)
Expand All @@ -1015,7 +1016,7 @@ void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdN
}
else
{
mICDClientStorage.RemoveKey(clientInfo);
getICDClientStorage()->RemoveKey(clientInfo);
ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(icdNodeId),
err.AsString());
}
Expand Down
3 changes: 0 additions & 3 deletions src/controller/java/AndroidDeviceControllerWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel

CHIP_ERROR FinishOTAProvider();

chip::app::DefaultICDClientStorage * getICDClientStorage() { return &mICDClientStorage; }

CHIP_ERROR SetICDCheckInDelegate(jobject checkInDelegate);

private:
Expand All @@ -228,7 +226,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
// 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;

Expand Down
99 changes: 99 additions & 0 deletions src/controller/java/AndroidICDClient.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
32 changes: 32 additions & 0 deletions src/controller/java/AndroidICDClient.h
Original file line number Diff line number Diff line change
@@ -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();
29 changes: 28 additions & 1 deletion src/controller/java/AndroidInteractionClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static CHIP_ERROR ParseDataVersionFilterList(jobject dataVersionFilterList,

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;
Expand Down Expand Up @@ -128,6 +128,9 @@ CHIP_ERROR subscribe(JNIEnv * env, jlong handle, jlong callbackHandle, jlong dev
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;
Expand Down Expand Up @@ -804,6 +807,30 @@ CHIP_ERROR invoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong device
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.
*/
Expand Down
5 changes: 4 additions & 1 deletion src/controller/java/AndroidInteractionClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -32,3 +32,6 @@ CHIP_ERROR invoke(JNIEnv * env, jlong handle, jlong callbackHandle, jlong device
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);
10 changes: 9 additions & 1 deletion src/controller/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@ source_set("android_chip_im_jni") {
"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",
]
Expand All @@ -70,6 +73,7 @@ source_set("android_chip_im_jni") {
}

deps = [
"${chip_root}/src/app/icd/client:manager",
"${chip_root}/src/lib",
"${chip_root}/src/lib/support/jsontlv",
"${chip_root}/src/platform",
Expand Down Expand Up @@ -136,6 +140,7 @@ shared_library("jni") {
"DeviceAttestationDelegateBridge.h",
"GroupDeviceProxy.h",
"MatterCallbacks-JNI.cpp",
"MatterICDClient-JNI.cpp",
"MatterInteractionClient-JNI.cpp",
]

Expand Down Expand Up @@ -431,12 +436,14 @@ kotlin_library("kotlin_matter_controller") {
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",
Expand Down Expand Up @@ -499,10 +506,12 @@ android_library("android_chip_im") {
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",
Expand Down Expand Up @@ -600,7 +609,6 @@ android_library("java") {
"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",
Expand Down
Loading

0 comments on commit 9565750

Please sign in to comment.