Skip to content

Commit dfab05d

Browse files
[Android] Implement check in delegate (project-chip#32557)
* Implement Android check in delegate * Restyled by whitespace * Restyled by google-java-format * Restyled by clang-format * Update documentation * Restyled by whitespace * Restyled by google-java-format * Fix jni object reference issue, add chiptool callback * Restyled by google-java-format * Restyled by clang-format * Update kotlin codestyle * remove public * fix typo * Restyled by clang-format * remove chip * Modify from comment --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 73d3147 commit dfab05d

10 files changed

+387
-2
lines changed

examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/ChipClient.kt

+19
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import android.util.Log
2222
import chip.devicecontroller.ChipDeviceController
2323
import chip.devicecontroller.ControllerParams
2424
import chip.devicecontroller.GetConnectedDeviceCallbackJni.GetConnectedDeviceCallback
25+
import chip.devicecontroller.ICDCheckInDelegate
26+
import chip.devicecontroller.ICDClientInfo
2527
import chip.platform.AndroidBleManager
2628
import chip.platform.AndroidChipPlatform
2729
import chip.platform.ChipMdnsCallbackImpl
@@ -60,6 +62,23 @@ object ChipClient {
6062
chipDeviceController.setAttestationTrustStoreDelegate(
6163
ExampleAttestationTrustStoreDelegate(chipDeviceController)
6264
)
65+
66+
chipDeviceController.setICDCheckInDelegate(
67+
object : ICDCheckInDelegate {
68+
override fun onCheckInComplete(info: ICDClientInfo) {
69+
Log.d(TAG, "onCheckInComplete : $info")
70+
}
71+
72+
override fun onKeyRefreshNeeded(info: ICDClientInfo): ByteArray? {
73+
Log.d(TAG, "onKeyRefreshNeeded : $info")
74+
return null
75+
}
76+
77+
override fun onKeyRefreshDone(errorCode: Long) {
78+
Log.d(TAG, "onKeyRefreshDone : $errorCode")
79+
}
80+
}
81+
)
6382
}
6483

6584
return chipDeviceController
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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+
#include "AndroidCheckInDelegate.h"
19+
20+
#include <app/icd/client/RefreshKeySender.h>
21+
#include <crypto/CHIPCryptoPAL.h>
22+
#include <lib/support/CodeUtils.h>
23+
#include <lib/support/JniReferences.h>
24+
#include <lib/support/logging/CHIPLogging.h>
25+
26+
#define PARSE_CLIENT_INFO(_clientInfo, _peerNodeId, _startCounter, _offset, _monitoredSubject, _jniICDAesKey, _jniICDHmacKey) \
27+
jlong _peerNodeId = static_cast<jlong>(_clientInfo.peer_node.GetNodeId()); \
28+
jlong _startCounter = static_cast<jlong>(_clientInfo.start_icd_counter); \
29+
jlong _offset = static_cast<jlong>(_clientInfo.offset); \
30+
jlong _monitoredSubject = static_cast<jlong>(_clientInfo.monitored_subject); \
31+
chip::ByteSpan aes_buf(_clientInfo.aes_key_handle.As<Crypto::Symmetric128BitsKeyByteArray>()); \
32+
chip::ByteSpan hmac_buf(_clientInfo.hmac_key_handle.As<Crypto::Symmetric128BitsKeyByteArray>()); \
33+
chip::ByteArray _jniICDAesKey(env, aes_buf); \
34+
chip::ByteArray _jniICDHmacKey(env, hmac_buf);
35+
36+
namespace chip {
37+
namespace app {
38+
39+
CHIP_ERROR AndroidCheckInDelegate::Init(ICDClientStorage * storage, InteractionModelEngine * engine)
40+
{
41+
VerifyOrReturnError(storage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
42+
VerifyOrReturnError(mpStorage == nullptr, CHIP_ERROR_INCORRECT_STATE);
43+
mpStorage = storage;
44+
mpImEngine = engine;
45+
return CHIP_NO_ERROR;
46+
}
47+
48+
CHIP_ERROR AndroidCheckInDelegate::SetDelegate(jobject checkInDelegateObj)
49+
{
50+
ReturnLogErrorOnFailure(mCheckInDelegate.Init(checkInDelegateObj));
51+
return CHIP_NO_ERROR;
52+
}
53+
54+
void AndroidCheckInDelegate::OnCheckInComplete(const ICDClientInfo & clientInfo)
55+
{
56+
ChipLogProgress(
57+
ICD, "Check In Message processing complete: start_counter=%" PRIu32 " offset=%" PRIu32 " nodeid=" ChipLogFormatScopedNodeId,
58+
clientInfo.start_icd_counter, clientInfo.offset, ChipLogValueScopedNodeId(clientInfo.peer_node));
59+
60+
VerifyOrReturn(mCheckInDelegate.HasValidObjectRef(), ChipLogProgress(ICD, "check-in delegate is not implemented!"));
61+
62+
JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
63+
VerifyOrReturn(env != nullptr, ChipLogError(Controller, "JNIEnv is null!"));
64+
PARSE_CLIENT_INFO(clientInfo, peerNodeId, startCounter, offset, monitoredSubject, jniICDAesKey, jniICDHmacKey)
65+
66+
jmethodID onCheckInCompleteMethodID = nullptr;
67+
CHIP_ERROR err = chip::JniReferences::GetInstance().FindMethod(env, mCheckInDelegate.ObjectRef(), "onCheckInComplete",
68+
"(JJJJ[B[B)V", &onCheckInCompleteMethodID);
69+
VerifyOrReturn(err == CHIP_NO_ERROR,
70+
ChipLogProgress(ICD, "onCheckInComplete - FindMethod is failed! : %" CHIP_ERROR_FORMAT, err.Format()));
71+
72+
env->CallVoidMethod(mCheckInDelegate.ObjectRef(), onCheckInCompleteMethodID, peerNodeId, startCounter, offset, monitoredSubject,
73+
jniICDAesKey.jniValue(), jniICDHmacKey.jniValue());
74+
}
75+
76+
RefreshKeySender * AndroidCheckInDelegate::OnKeyRefreshNeeded(ICDClientInfo & clientInfo, ICDClientStorage * clientStorage)
77+
{
78+
CHIP_ERROR err = CHIP_NO_ERROR;
79+
RefreshKeySender::RefreshKeyBuffer newKey;
80+
81+
bool hasSetKey = false;
82+
if (mCheckInDelegate.HasValidObjectRef())
83+
{
84+
JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
85+
VerifyOrReturnValue(env != nullptr, nullptr, ChipLogError(Controller, "JNIEnv is null!"));
86+
87+
PARSE_CLIENT_INFO(clientInfo, peerNodeId, startCounter, offset, monitoredSubject, jniICDAesKey, jniICDHmacKey)
88+
89+
jmethodID onKeyRefreshNeededMethodID = nullptr;
90+
err = chip::JniReferences::GetInstance().FindMethod(env, mCheckInDelegate.ObjectRef(), "onKeyRefreshNeeded", "(JJJJ[B[B)V",
91+
&onKeyRefreshNeededMethodID);
92+
VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr,
93+
ChipLogProgress(ICD, "onKeyRefreshNeeded - FindMethod is failed! : %" CHIP_ERROR_FORMAT, err.Format()));
94+
95+
jbyteArray key = static_cast<jbyteArray>(env->CallObjectMethod(mCheckInDelegate.ObjectRef(), onKeyRefreshNeededMethodID,
96+
peerNodeId, startCounter, offset, monitoredSubject,
97+
jniICDAesKey.jniValue(), jniICDHmacKey.jniValue()));
98+
99+
if (key != nullptr)
100+
{
101+
JniByteArray jniKey(env, key);
102+
VerifyOrReturnValue(static_cast<size_t>(jniKey.size()) == newKey.Capacity(), nullptr,
103+
ChipLogProgress(ICD, "Invalid key length : %d", jniKey.size()));
104+
memcpy(newKey.Bytes(), jniKey.data(), newKey.Capacity());
105+
hasSetKey = true;
106+
}
107+
}
108+
else
109+
{
110+
ChipLogProgress(ICD, "check-in delegate is not implemented!");
111+
}
112+
if (!hasSetKey)
113+
{
114+
err = Crypto::DRBG_get_bytes(newKey.Bytes(), newKey.Capacity());
115+
if (err != CHIP_NO_ERROR)
116+
{
117+
ChipLogError(ICD, "Generation of new key failed: %" CHIP_ERROR_FORMAT, err.Format());
118+
return nullptr;
119+
}
120+
}
121+
122+
auto refreshKeySender = Platform::New<RefreshKeySender>(this, clientInfo, clientStorage, mpImEngine, newKey);
123+
if (refreshKeySender == nullptr)
124+
{
125+
return nullptr;
126+
}
127+
return refreshKeySender;
128+
}
129+
130+
void AndroidCheckInDelegate::OnKeyRefreshDone(RefreshKeySender * refreshKeySender, CHIP_ERROR error)
131+
{
132+
if (error == CHIP_NO_ERROR)
133+
{
134+
ChipLogProgress(ICD, "Re-registration with new key completed successfully");
135+
}
136+
else
137+
{
138+
ChipLogError(ICD, "Re-registration with new key failed with error : %" CHIP_ERROR_FORMAT, error.Format());
139+
// The callee can take corrective action based on the error received.
140+
}
141+
142+
VerifyOrReturn(mCheckInDelegate.HasValidObjectRef(), ChipLogProgress(ICD, "check-in delegate is not implemented!"));
143+
144+
JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
145+
VerifyOrReturn(env != nullptr, ChipLogError(Controller, "JNIEnv is null!"));
146+
147+
jmethodID onKeyRefreshDoneMethodID = nullptr;
148+
CHIP_ERROR err = chip::JniReferences::GetInstance().FindMethod(env, mCheckInDelegate.ObjectRef(), "onKeyRefreshDone", "(J)V",
149+
&onKeyRefreshDoneMethodID);
150+
VerifyOrReturn(err == CHIP_NO_ERROR,
151+
ChipLogProgress(ICD, "onKeyRefreshDone - FindMethod is failed! : %" CHIP_ERROR_FORMAT, err.Format()));
152+
153+
env->CallVoidMethod(mCheckInDelegate.ObjectRef(), onKeyRefreshDoneMethodID, static_cast<jlong>(error.AsInteger()));
154+
155+
if (refreshKeySender != nullptr)
156+
{
157+
Platform::Delete(refreshKeySender);
158+
refreshKeySender = nullptr;
159+
}
160+
}
161+
} // namespace app
162+
} // namespace chip
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <app/icd/client/CheckInDelegate.h>
22+
#include <app/icd/client/ICDClientStorage.h>
23+
#include <lib/support/JniTypeWrappers.h>
24+
25+
namespace chip {
26+
namespace app {
27+
28+
using namespace std;
29+
30+
class InteractionModelEngine;
31+
32+
/// Callbacks for check in protocol
33+
class AndroidCheckInDelegate : public CheckInDelegate
34+
{
35+
public:
36+
virtual ~AndroidCheckInDelegate() {}
37+
CHIP_ERROR Init(ICDClientStorage * storage, InteractionModelEngine * engine);
38+
void OnCheckInComplete(const ICDClientInfo & clientInfo) override;
39+
RefreshKeySender * OnKeyRefreshNeeded(ICDClientInfo & clientInfo, ICDClientStorage * clientStorage) override;
40+
void OnKeyRefreshDone(RefreshKeySender * refreshKeySender, CHIP_ERROR error) override;
41+
42+
CHIP_ERROR SetDelegate(jobject checkInDelegateObj);
43+
44+
private:
45+
ICDClientStorage * mpStorage = nullptr;
46+
InteractionModelEngine * mpImEngine = nullptr;
47+
48+
JniGlobalReference mCheckInDelegate;
49+
};
50+
51+
} // namespace app
52+
} // namespace chip

src/controller/java/AndroidDeviceControllerWrapper.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,11 @@ CHIP_ERROR AndroidDeviceControllerWrapper::FinishOTAProvider()
689689
#endif
690690
}
691691

692+
CHIP_ERROR AndroidDeviceControllerWrapper::SetICDCheckInDelegate(jobject checkInDelegate)
693+
{
694+
return mCheckInDelegate.SetDelegate(checkInDelegate);
695+
}
696+
692697
void AndroidDeviceControllerWrapper::OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status)
693698
{
694699
chip::DeviceLayer::StackUnlock unlock;

src/controller/java/AndroidDeviceControllerWrapper.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include <jni.h>
2626

2727
#include <app/icd/client/CheckInHandler.h>
28-
#include <app/icd/client/DefaultCheckInDelegate.h>
2928
#include <app/icd/client/DefaultICDClientStorage.h>
3029
#include <controller/CHIPDeviceController.h>
3130
#include <credentials/GroupDataProviderImpl.h>
@@ -43,6 +42,7 @@
4342
#include <platform/android/CHIPP256KeypairBridge.h>
4443
#endif // JAVA_MATTER_CONTROLLER_TEST
4544

45+
#include "AndroidCheckInDelegate.h"
4646
#include "AndroidOperationalCredentialsIssuer.h"
4747
#include "AttestationTrustStoreBridge.h"
4848
#include "DeviceAttestationDelegateBridge.h"
@@ -212,6 +212,8 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
212212

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

215+
CHIP_ERROR SetICDCheckInDelegate(jobject checkInDelegate);
216+
215217
private:
216218
using ChipDeviceControllerPtr = std::unique_ptr<chip::Controller::DeviceCommissioner>;
217219

@@ -225,7 +227,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
225227
chip::Crypto::RawKeySessionKeystore mSessionKeystore;
226228

227229
chip::app::DefaultICDClientStorage mICDClientStorage;
228-
chip::app::DefaultCheckInDelegate mCheckInDelegate;
230+
chip::app::AndroidCheckInDelegate mCheckInDelegate;
229231
chip::app::CheckInHandler mCheckInHandler;
230232

231233
JavaVM * mJavaVM = nullptr;

src/controller/java/BUILD.gn

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ shared_library("jni") {
4141
"AndroidCallbacks-JNI.cpp",
4242
"AndroidCallbacks.cpp",
4343
"AndroidCallbacks.h",
44+
"AndroidCheckInDelegate.cpp",
45+
"AndroidCheckInDelegate.h",
4446
"AndroidClusterExceptions.cpp",
4547
"AndroidClusterExceptions.h",
4648
"AndroidCommissioningWindowOpener.cpp",
@@ -459,6 +461,8 @@ android_library("java") {
459461
"src/chip/devicecontroller/ExtendableInvokeCallbackJni.java",
460462
"src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java",
461463
"src/chip/devicecontroller/GroupKeySecurityPolicy.java",
464+
"src/chip/devicecontroller/ICDCheckInDelegate.java",
465+
"src/chip/devicecontroller/ICDCheckInDelegateWrapper.java",
462466
"src/chip/devicecontroller/ICDClientInfo.java",
463467
"src/chip/devicecontroller/ICDDeviceInfo.java",
464468
"src/chip/devicecontroller/ICDRegistrationInfo.java",

src/controller/java/CHIPDeviceController-JNI.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,25 @@ JNI_METHOD(void, finishOTAProvider)(JNIEnv * env, jobject self, jlong handle)
588588
#endif
589589
}
590590

591+
JNI_METHOD(void, setICDCheckInDelegate)(JNIEnv * env, jobject self, jlong handle, jobject checkInDelegate)
592+
{
593+
chip::DeviceLayer::StackLock lock;
594+
CHIP_ERROR err = CHIP_NO_ERROR;
595+
AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle);
596+
597+
VerifyOrExit(wrapper != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
598+
599+
ChipLogProgress(Controller, "setICDCheckInDelegate() called");
600+
601+
err = wrapper->SetICDCheckInDelegate(checkInDelegate);
602+
exit:
603+
if (err != CHIP_NO_ERROR)
604+
{
605+
ChipLogError(Controller, "Failed to set ICD Check-In Deleagate. : %" CHIP_ERROR_FORMAT, err.Format());
606+
JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
607+
}
608+
}
609+
591610
JNI_METHOD(void, commissionDevice)
592611
(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jbyteArray csrNonce, jobject networkCredentials)
593612
{

src/controller/java/src/chip/devicecontroller/ChipDeviceController.java

+8
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ public void finishOTAProvider() {
151151
finishOTAProvider(deviceControllerPtr);
152152
}
153153

154+
/** Set the delegate of ICD check in */
155+
public void setICDCheckInDelegate(ICDCheckInDelegate delegate) {
156+
setICDCheckInDelegate(deviceControllerPtr, new ICDCheckInDelegateWrapper(delegate));
157+
}
158+
154159
public void pairDevice(
155160
BluetoothGatt bleServer,
156161
int connId,
@@ -1434,6 +1439,9 @@ private native void setAttestationTrustStoreDelegate(
14341439

14351440
private native void finishOTAProvider(long deviceControllerPtr);
14361441

1442+
private native void setICDCheckInDelegate(
1443+
long deviceControllerPtr, ICDCheckInDelegateWrapper delegate);
1444+
14371445
private native void pairDevice(
14381446
long deviceControllerPtr,
14391447
long deviceId,

0 commit comments

Comments
 (0)