/* * Copyright (c) 2020-2022 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 JNI bridge for CHIP Device Controller for Android apps * */ #include "AndroidCallbacks.h" #include "AndroidCommissioningWindowOpener.h" #include "AndroidCurrentFabricRemover.h" #include "AndroidDeviceControllerWrapper.h" #include "AndroidInteractionClient.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if CHIP_DEVICE_CONFIG_DYNAMIC_SERVER #include #endif // CHIP_DEVICE_CONFIG_DYNAMIC_SERVER #ifdef JAVA_MATTER_CONTROLLER_TEST #include #else #include #endif // Choose an approximation of PTHREAD_NULL if pthread.h doesn't define one. #ifndef PTHREAD_NULL #define PTHREAD_NULL 0 #endif // PTHREAD_NULL using namespace chip; using namespace chip::Inet; using namespace chip::Controller; using namespace chip::Credentials; using namespace chip::Crypto; #define JNI_METHOD(RETURN, METHOD_NAME) \ extern "C" JNIEXPORT RETURN JNICALL Java_chip_devicecontroller_ChipDeviceController_##METHOD_NAME #define CDC_JNI_CALLBACK_LOCAL_REF_COUNT 256 static void * IOThreadMain(void * arg); static CHIP_ERROR StopIOThread(); static CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jbyteArray pakeVerifier, jobject & outParams); static CHIP_ERROR N2J_NetworkLocation(JNIEnv * env, jstring ipAddress, jint port, jint interfaceIndex, jobject & outLocation); namespace { JavaVM * sJVM = nullptr; pthread_t sIOThread = PTHREAD_NULL; chip::JniGlobalReference sChipDeviceControllerExceptionCls; } // namespace // NOTE: Remote device ID is in sync with the echo server device id // At some point, we may want to add an option to connect to a device without // knowing its id, because the ID can be learned on the first response that is received. chip::NodeId kLocalDeviceId = chip::kTestControllerNodeId; chip::NodeId kRemoteDeviceId = chip::kTestDeviceNodeId; jint JNI_OnLoad(JavaVM * jvm, void * reserved) { CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env; ChipLogProgress(Controller, "JNI_OnLoad() called"); chip::Platform::MemoryInit(); // Save a reference to the JVM. Will need this to call back into Java. JniReferences::GetInstance().SetJavaVm(jvm, "chip/devicecontroller/ChipDeviceController"); sJVM = jvm; // Get a JNI environment object. env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrExit(env != nullptr, err = CHIP_JNI_ERROR_NO_ENV); ChipLogProgress(Controller, "Loading Java class references."); // Get various class references need by the API. jclass controllerExceptionCls; err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/ChipDeviceControllerException", controllerExceptionCls); SuccessOrExit(err = sChipDeviceControllerExceptionCls.Init(controllerExceptionCls)); ChipLogProgress(Controller, "Java class references loaded."); #ifndef JAVA_MATTER_CONTROLLER_TEST err = AndroidChipPlatformJNI_OnLoad(jvm, reserved); SuccessOrExit(err); #endif // JAVA_MATTER_CONTROLLER_TEST #if CHIP_DEVICE_CONFIG_DYNAMIC_SERVER chip::app::dynamic_server::InitAccessControl(); #endif // CHIP_DEVICE_CONFIG_DYNAMIC_SERVER exit: if (err != CHIP_NO_ERROR) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); chip::DeviceLayer::StackUnlock unlock; JNI_OnUnload(jvm, reserved); } return (err == CHIP_NO_ERROR) ? JNI_VERSION_1_6 : JNI_ERR; } void JNI_OnUnload(JavaVM * jvm, void * reserved) { chip::DeviceLayer::StackLock lock; ChipLogProgress(Controller, "JNI_OnUnload() called"); // If the IO thread has not been stopped yet, shut it down now. // TODO(arkq): Maybe we should just assert here, as the IO thread // should be stopped before the library is unloaded. StopIOThread(); sJVM = nullptr; chip::Platform::MemoryShutdown(); } JNI_METHOD(jlong, onNOCChainGeneration) (JNIEnv * env, jobject self, jlong handle, jobject controllerParams) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "setNOCChain() called"); jmethodID getRootCertificate; jmethodID getIntermediateCertificate; jmethodID getOperationalCertificate; jmethodID getIpk; jmethodID getAdminSubject; jbyteArray rootCertificate = nullptr; jbyteArray intermediateCertificate = nullptr; jbyteArray operationalCertificate = nullptr; jbyteArray ipk = nullptr; Optional adminSubjectOptional; uint64_t adminSubject = chip::kUndefinedNodeId; CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); Optional ipkOptional; uint8_t ipkValue[CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; Crypto::IdentityProtectionKeySpan ipkTempSpan(ipkValue); VerifyOrExit(controllerParams != nullptr, ChipLogError(Controller, "controllerParams is null!")); err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getRootCertificate", "()[B", &getRootCertificate); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Find getRootCertificate method fail!")); err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getIntermediateCertificate", "()[B", &getIntermediateCertificate); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Find getIntermediateCertificate method fail!")); err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getOperationalCertificate", "()[B", &getOperationalCertificate); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Find getOperationalCertificate method fail!")); err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getIpk", "()[B", &getIpk); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Find getIpk method fail!")); err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getAdminSubject", "()J", &getAdminSubject); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Find getAdminSubject method fail!")); rootCertificate = static_cast(env->CallObjectMethod(controllerParams, getRootCertificate)); VerifyOrExit(rootCertificate != nullptr, err = CHIP_ERROR_BAD_REQUEST); intermediateCertificate = static_cast(env->CallObjectMethod(controllerParams, getIntermediateCertificate)); VerifyOrExit(intermediateCertificate != nullptr, err = CHIP_ERROR_BAD_REQUEST); operationalCertificate = static_cast(env->CallObjectMethod(controllerParams, getOperationalCertificate)); VerifyOrExit(operationalCertificate != nullptr, err = CHIP_ERROR_BAD_REQUEST); ipk = static_cast(env->CallObjectMethod(controllerParams, getIpk)); if (ipk != nullptr) { JniByteArray jByteArrayIpk(env, ipk); if (jByteArrayIpk.byteSpan().size() != sizeof(ipkValue)) { ChipLogError(Controller, "Invalid IPK size %u and expect %u", static_cast(jByteArrayIpk.byteSpan().size()), static_cast(sizeof(ipkValue))); ExitNow(err = CHIP_ERROR_INVALID_IPK); } memcpy(&ipkValue[0], jByteArrayIpk.byteSpan().data(), jByteArrayIpk.byteSpan().size()); ipkOptional.SetValue(ipkTempSpan); } else if (commissioningParams.GetIpk().HasValue()) { // if no value pass in ControllerParams, use value from CommissioningParameters ipkOptional.SetValue(commissioningParams.GetIpk().Value()); } adminSubject = static_cast(env->CallLongMethod(controllerParams, getAdminSubject)); if (adminSubject == kUndefinedNodeId) { // if no value pass in ControllerParams, use value from CommissioningParameters adminSubject = commissioningParams.GetAdminSubject().ValueOr(kUndefinedNodeId); } if (adminSubject != kUndefinedNodeId) { adminSubjectOptional.SetValue(adminSubject); } // NOTE: we are allowing adminSubject to not be set since the OnNOCChainGeneration callback makes this field // optional and includes logic to handle the case where it is not set. It would also make sense to return // an error here since that use case may not be realistic. { JniByteArray jByteArrayRcac(env, rootCertificate); JniByteArray jByteArrayIcac(env, intermediateCertificate); JniByteArray jByteArrayNoc(env, operationalCertificate); #ifndef JAVA_MATTER_CONTROLLER_TEST err = wrapper->GetAndroidOperationalCredentialsIssuer()->NOCChainGenerated( CHIP_NO_ERROR, jByteArrayNoc.byteSpan(), jByteArrayIcac.byteSpan(), jByteArrayRcac.byteSpan(), ipkOptional, adminSubjectOptional); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to SetNocChain for the device: %" CHIP_ERROR_FORMAT, err.Format()); } return static_cast(err.AsInteger()); #endif // JAVA_MATTER_CONTROLLER_TEST } exit: #ifndef JAVA_MATTER_CONTROLLER_TEST err = wrapper->GetAndroidOperationalCredentialsIssuer()->NOCChainGenerated(err, ByteSpan(), ByteSpan(), ByteSpan(), ipkOptional, adminSubjectOptional); #endif // JAVA_MATTER_CONTROLLER_TEST return static_cast(err.AsInteger()); } JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject controllerParams) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = nullptr; jlong result = 0; ChipLogProgress(Controller, "newDeviceController() called"); // Retrieve initialization params. jmethodID getFabricId; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getFabricId", "()J", &getFabricId); SuccessOrExit(err); jmethodID getUdpListenPort; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getUdpListenPort", "()I", &getUdpListenPort); SuccessOrExit(err); jmethodID getControllerVendorId; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getControllerVendorId", "()I", &getControllerVendorId); jmethodID getFailsafeTimerSeconds; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getFailsafeTimerSeconds", "()I", &getFailsafeTimerSeconds); SuccessOrExit(err); jmethodID getCASEFailsafeTimerSeconds; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getCASEFailsafeTimerSeconds", "()I", &getCASEFailsafeTimerSeconds); SuccessOrExit(err); jmethodID getAttemptNetworkScanWiFi; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getAttemptNetworkScanWiFi", "()Z", &getAttemptNetworkScanWiFi); SuccessOrExit(err); jmethodID getAttemptNetworkScanThread; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getAttemptNetworkScanThread", "()Z", &getAttemptNetworkScanThread); SuccessOrExit(err); jmethodID getSkipCommissioningComplete; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getSkipCommissioningComplete", "()Z", &getSkipCommissioningComplete); SuccessOrExit(err); jmethodID getSkipAttestationCertificateValidation; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getSkipAttestationCertificateValidation", "()Z", &getSkipAttestationCertificateValidation); SuccessOrExit(err); jmethodID getCountryCode; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getCountryCode", "()Ljava/util/Optional;", &getCountryCode); SuccessOrExit(err); jmethodID getRegulatoryLocation; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getRegulatoryLocation", "()Ljava/util/Optional;", &getRegulatoryLocation); SuccessOrExit(err); jmethodID getKeypairDelegate; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getKeypairDelegate", "()Lchip/devicecontroller/KeypairDelegate;", &getKeypairDelegate); SuccessOrExit(err); jmethodID getRootCertificate; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getRootCertificate", "()[B", &getRootCertificate); SuccessOrExit(err); jmethodID getIntermediateCertificate; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getIntermediateCertificate", "()[B", &getIntermediateCertificate); SuccessOrExit(err); jmethodID getOperationalCertificate; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getOperationalCertificate", "()[B", &getOperationalCertificate); SuccessOrExit(err); jmethodID getIpk; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getIpk", "()[B", &getIpk); SuccessOrExit(err); jmethodID getAdminSubject; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getAdminSubject", "()J", &getAdminSubject); SuccessOrExit(err); jmethodID getEnableServerInteractions; err = chip::JniReferences::GetInstance().FindMethod(env, controllerParams, "getEnableServerInteractions", "()Z", &getEnableServerInteractions); SuccessOrExit(err); { uint64_t fabricId = static_cast(env->CallLongMethod(controllerParams, getFabricId)); uint16_t listenPort = static_cast(env->CallIntMethod(controllerParams, getUdpListenPort)); uint16_t controllerVendorId = static_cast(env->CallIntMethod(controllerParams, getControllerVendorId)); jobject keypairDelegate = env->CallObjectMethod(controllerParams, getKeypairDelegate); jbyteArray rootCertificate = (jbyteArray) env->CallObjectMethod(controllerParams, getRootCertificate); jbyteArray intermediateCertificate = (jbyteArray) env->CallObjectMethod(controllerParams, getIntermediateCertificate); jbyteArray operationalCertificate = (jbyteArray) env->CallObjectMethod(controllerParams, getOperationalCertificate); jbyteArray ipk = (jbyteArray) env->CallObjectMethod(controllerParams, getIpk); uint16_t failsafeTimerSeconds = static_cast(env->CallIntMethod(controllerParams, getFailsafeTimerSeconds)); uint16_t caseFailsafeTimerSeconds = static_cast(env->CallIntMethod(controllerParams, getCASEFailsafeTimerSeconds)); bool attemptNetworkScanWiFi = env->CallBooleanMethod(controllerParams, getAttemptNetworkScanWiFi); bool attemptNetworkScanThread = env->CallBooleanMethod(controllerParams, getAttemptNetworkScanThread); bool skipCommissioningComplete = env->CallBooleanMethod(controllerParams, getSkipCommissioningComplete); bool skipAttestationCertificateValidation = env->CallBooleanMethod(controllerParams, getSkipAttestationCertificateValidation); uint64_t adminSubject = static_cast(env->CallLongMethod(controllerParams, getAdminSubject)); jobject countryCodeOptional = env->CallObjectMethod(controllerParams, getCountryCode); jobject regulatoryLocationOptional = env->CallObjectMethod(controllerParams, getRegulatoryLocation); bool enableServerInteractions = env->CallBooleanMethod(controllerParams, getEnableServerInteractions) == JNI_TRUE; jobject countryCode; err = chip::JniReferences::GetInstance().GetOptionalValue(countryCodeOptional, countryCode); SuccessOrExit(err); #ifdef JAVA_MATTER_CONTROLLER_TEST std::unique_ptr opCredsIssuer( new chip::Controller::ExampleOperationalCredentialsIssuer()); #else std::unique_ptr opCredsIssuer( new chip::Controller::AndroidOperationalCredentialsIssuer()); #endif wrapper = AndroidDeviceControllerWrapper::AllocateNew( sJVM, self, kLocalDeviceId, fabricId, chip::kUndefinedCATs, &DeviceLayer::SystemLayer(), DeviceLayer::TCPEndPointManager(), DeviceLayer::UDPEndPointManager(), std::move(opCredsIssuer), keypairDelegate, rootCertificate, intermediateCertificate, operationalCertificate, ipk, listenPort, controllerVendorId, failsafeTimerSeconds, attemptNetworkScanWiFi, attemptNetworkScanThread, skipCommissioningComplete, skipAttestationCertificateValidation, static_cast(countryCode), enableServerInteractions, &err); SuccessOrExit(err); if (caseFailsafeTimerSeconds > 0) { CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); commissioningParams.SetCASEFailsafeTimerSeconds(caseFailsafeTimerSeconds); err = wrapper->UpdateCommissioningParameters(commissioningParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); SuccessOrExit(err); } } if (adminSubject != kUndefinedNodeId) { // if there is a valid adminSubject in the ControllerParams, then remember it CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); commissioningParams.SetAdminSubject(adminSubject); err = wrapper->UpdateCommissioningParameters(commissioningParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); SuccessOrExit(err); } } jobject regulatoryLocation; err = chip::JniReferences::GetInstance().GetOptionalValue(regulatoryLocationOptional, regulatoryLocation); SuccessOrExit(err); if (regulatoryLocation != nullptr) { using namespace app::Clusters::GeneralCommissioning; jint regulatoryLocationJint = chip::JniReferences::GetInstance().IntegerToPrimitive(regulatoryLocation); VerifyOrExit(chip::CanCastTo(regulatoryLocationJint), err = CHIP_ERROR_INVALID_ARGUMENT); auto regulatoryLocationType = static_cast(regulatoryLocationJint); VerifyOrExit(regulatoryLocationType >= RegulatoryLocationTypeEnum::kIndoor, err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(regulatoryLocationType <= RegulatoryLocationTypeEnum::kIndoorOutdoor, err = CHIP_ERROR_INVALID_ARGUMENT); chip::Controller::CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); commissioningParams.SetDeviceRegulatoryLocation(regulatoryLocationType); err = wrapper->UpdateCommissioningParameters(commissioningParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); SuccessOrExit(err); } } } // Create and start the IO thread. Must be called after Controller()->Init if (sIOThread == PTHREAD_NULL) { int pthreadErr = pthread_create(&sIOThread, nullptr, IOThreadMain, nullptr); VerifyOrExit(pthreadErr == 0, err = CHIP_ERROR_POSIX(pthreadErr)); } result = wrapper->ToJNIHandle(); exit: if (err != CHIP_NO_ERROR) { if (wrapper != nullptr) { delete wrapper; } if (err != CHIP_JNI_ERROR_EXCEPTION_THROWN) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } return result; } JNI_METHOD(void, setDeviceAttestationDelegate) (JNIEnv * env, jobject self, jlong handle, jint failSafeExpiryTimeoutSecs, jobject deviceAttestationDelegate) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "setDeviceAttestationDelegate() called"); if (deviceAttestationDelegate != nullptr) { chip::Optional timeoutSecs = chip::MakeOptional(static_cast(failSafeExpiryTimeoutSecs)); bool shouldWaitAfterDeviceAttestation = false; jclass deviceAttestationDelegateCls = nullptr; JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/DeviceAttestationDelegate", deviceAttestationDelegateCls); VerifyOrExit(deviceAttestationDelegateCls != nullptr, err = CHIP_JNI_ERROR_TYPE_NOT_FOUND); if (env->IsInstanceOf(deviceAttestationDelegate, deviceAttestationDelegateCls)) { shouldWaitAfterDeviceAttestation = true; } err = wrapper->UpdateDeviceAttestationDelegateBridge(deviceAttestationDelegate, timeoutSecs, shouldWaitAfterDeviceAttestation); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to set device attestation delegate."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, setAttestationTrustStoreDelegate) (JNIEnv * env, jobject self, jlong handle, jobject attestationTrustStoreDelegate, jobject cdTrustKeys) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "setAttestationTrustStoreDelegate() called"); if (attestationTrustStoreDelegate != nullptr) { err = wrapper->UpdateAttestationTrustStoreBridge(attestationTrustStoreDelegate, cdTrustKeys); SuccessOrExit(err); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to set device attestation delegate."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, startOTAProvider)(JNIEnv * env, jobject self, jlong handle, jobject otaProviderDelegate) { #if CHIP_DEVICE_CONFIG_DYNAMIC_SERVER chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrExit(wrapper != nullptr, err = CHIP_ERROR_INCORRECT_STATE); ChipLogProgress(Controller, "startOTAProvider() called"); err = wrapper->StartOTAProvider(otaProviderDelegate); exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to start OTA Provider. : %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } #endif } JNI_METHOD(void, finishOTAProvider)(JNIEnv * env, jobject self, jlong handle) { #if CHIP_DEVICE_CONFIG_DYNAMIC_SERVER chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrExit(wrapper != nullptr, err = CHIP_ERROR_INCORRECT_STATE); ChipLogProgress(Controller, "finishOTAProvider() called"); err = wrapper->FinishOTAProvider(); exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to finish OTA Provider. : %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } #endif } JNI_METHOD(void, setICDCheckInDelegate)(JNIEnv * env, jobject self, jlong handle, jobject checkInDelegate) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrExit(wrapper != nullptr, err = CHIP_ERROR_INCORRECT_STATE); ChipLogProgress(Controller, "setICDCheckInDelegate() called"); err = wrapper->SetICDCheckInDelegate(checkInDelegate); exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to set ICD Check-In Deleagate. : %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, commissionDevice) (JNIEnv * env, jobject self, jlong handle, jlong deviceId, jbyteArray csrNonce, jobject networkCredentials, jobject icdRegistrationInfo) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "commissionDevice() called"); CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); if (networkCredentials != nullptr) { err = wrapper->ApplyNetworkCredentials(commissioningParams, networkCredentials); VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_ERROR_INVALID_ARGUMENT); } commissioningParams.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete); wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); if (wrapper->GetDeviceAttestationDelegateBridge() != nullptr) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); } if (csrNonce != nullptr) { JniByteArray jniCsrNonce(env, csrNonce); commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan()); } err = wrapper->Controller()->Commission(static_cast(deviceId), commissioningParams); exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to commission the device."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, pairDevice) (JNIEnv * env, jobject self, jlong handle, jlong deviceId, jint connObj, jlong pinCode, jbyteArray csrNonce, jobject networkCredentials, jobject icdRegistrationInfo) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "pairDevice() called with device ID, connection object, and pincode"); if (!chip::CanCastTo(pinCode)) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INVALID_ARGUMENT); return; } RendezvousParameters rendezvousParams = RendezvousParameters() .SetSetupPINCode(static_cast(pinCode)) #if CONFIG_NETWORK_LAYER_BLE .SetConnectionObject(reinterpret_cast(connObj)) #endif .SetPeerAddress(Transport::PeerAddress::BLE()); CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); wrapper->ApplyNetworkCredentials(commissioningParams, networkCredentials); if (csrNonce != nullptr) { JniByteArray jniCsrNonce(env, csrNonce); commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan()); } commissioningParams.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete); wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); if (wrapper->GetDeviceAttestationDelegateBridge() != nullptr) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); } err = wrapper->Controller()->PairDevice(static_cast(deviceId), rendezvousParams, commissioningParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to pair the device."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, pairDeviceWithAddress) (JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring address, jint port, jint discriminator, jlong pinCode, jbyteArray csrNonce, jobject icdRegistrationInfo) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "pairDeviceWithAddress() called"); if (!chip::CanCastTo(pinCode)) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INVALID_ARGUMENT); return; } JniUtfString addrJniString(env, address); RendezvousParameters rendezvousParams = RendezvousParameters() .SetDiscriminator(static_cast(discriminator)) .SetSetupPINCode(static_cast(pinCode)) .SetPeerAddress(Transport::PeerAddress::UDP(const_cast(addrJniString.c_str()), static_cast(port))); CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); if (csrNonce != nullptr) { JniByteArray jniCsrNonce(env, csrNonce); commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan()); } commissioningParams.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete); wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); if (wrapper->GetDeviceAttestationDelegateBridge() != nullptr) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); } err = wrapper->Controller()->PairDevice(static_cast(deviceId), rendezvousParams, commissioningParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to pair the device."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, pairDeviceWithCode) (JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring setUpCode, jboolean discoverOnce, jboolean useOnlyOnNetworkDiscovery, jbyteArray csrNonce, jobject networkCredentials, jobject icdRegistrationInfo) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "pairDeviceWithCode() called"); JniUtfString setUpCodeJniString(env, setUpCode); CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); auto discoveryType = DiscoveryType::kAll; if (useOnlyOnNetworkDiscovery) { discoveryType = DiscoveryType::kDiscoveryNetworkOnly; } if (discoverOnce) { discoveryType = DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry; } if (csrNonce != nullptr) { JniByteArray jniCsrNonce(env, csrNonce); commissioningParams.SetCSRNonce(jniCsrNonce.byteSpan()); } if (networkCredentials != nullptr) { wrapper->ApplyNetworkCredentials(commissioningParams, networkCredentials); } commissioningParams.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete); wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); if (wrapper->GetDeviceAttestationDelegateBridge() != nullptr) { commissioningParams.SetDeviceAttestationDelegate(wrapper->GetDeviceAttestationDelegateBridge()); } err = wrapper->Controller()->PairDevice(static_cast(deviceId), setUpCodeJniString.c_str(), commissioningParams, discoveryType); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to pair the device."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, establishPaseConnection)(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jint connObj, jlong pinCode) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); if (!chip::CanCastTo(pinCode)) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INVALID_ARGUMENT); return; } RendezvousParameters rendezvousParams = RendezvousParameters() .SetSetupPINCode(static_cast(pinCode)) #if CONFIG_NETWORK_LAYER_BLE .SetConnectionObject(reinterpret_cast(connObj)) #endif .SetPeerAddress(Transport::PeerAddress::BLE()); err = wrapper->Controller()->EstablishPASEConnection(static_cast(deviceId), rendezvousParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to establish PASE connection."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, establishPaseConnectionByAddress) (JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring address, jint port, jlong pinCode) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); if (!chip::CanCastTo(pinCode)) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INVALID_ARGUMENT); return; } JniUtfString addrJniString(env, address); RendezvousParameters rendezvousParams = RendezvousParameters() .SetSetupPINCode(static_cast(pinCode)) .SetPeerAddress(Transport::PeerAddress::UDP(const_cast(addrJniString.c_str()), static_cast(port))); err = wrapper->Controller()->EstablishPASEConnection(static_cast(deviceId), rendezvousParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to establish PASE connection."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, establishPaseConnectionByCode) (JNIEnv * env, jobject self, jlong handle, jlong deviceId, jstring setUpCode, jboolean useOnlyOnNetworkDiscovery) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); auto discoveryType = DiscoveryType::kAll; if (useOnlyOnNetworkDiscovery) { discoveryType = DiscoveryType::kDiscoveryNetworkOnly; } JniUtfString setUpCodeJniString(env, setUpCode); err = wrapper->Controller()->EstablishPASEConnection(static_cast(deviceId), setUpCodeJniString.c_str(), discoveryType); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to establish PASE connection."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, continueCommissioning) (JNIEnv * env, jobject self, jlong handle, jlong devicePtr, jboolean ignoreAttestationFailure) { chip::DeviceLayer::StackLock lock; ChipLogProgress(Controller, "continueCommissioning() called."); CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); DeviceAttestationDelegateBridge * deviceAttestationDelegateBridge = wrapper->GetDeviceAttestationDelegateBridge(); auto lastAttestationResult = deviceAttestationDelegateBridge ? deviceAttestationDelegateBridge->attestationVerificationResult() : chip::Credentials::AttestationVerificationResult::kSuccess; chip::DeviceProxy * deviceProxy = reinterpret_cast(devicePtr); err = wrapper->Controller()->ContinueCommissioningAfterDeviceAttestation( deviceProxy, ignoreAttestationFailure ? chip::Credentials::AttestationVerificationResult::kSuccess : lastAttestationResult); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to continue commissioning."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, setUseJavaCallbackForNOCRequest) (JNIEnv * env, jobject self, jlong handle, jboolean useCallback) { ChipLogProgress(Controller, "setUseJavaCallbackForNOCRequest() called"); chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); #ifndef JAVA_MATTER_CONTROLLER_TEST wrapper->GetAndroidOperationalCredentialsIssuer()->SetUseJavaCallbackForNOCRequest(useCallback); #endif if (useCallback) { // if we are assigning a callback, then make the device commissioner delegate verification to the // PartialDACVerifier so that DAC chain and CD validation can be performed by custom code // triggered by ChipDeviceController.NOCChainIssuer.onNOCChainGenerationNeeded(). wrapper->Controller()->SetDeviceAttestationVerifier(wrapper->GetPartialDACVerifier()); } else { // if we are setting callback to null, then make the device commissioner use the default verifier wrapper->Controller()->SetDeviceAttestationVerifier(GetDeviceAttestationVerifier()); } } JNI_METHOD(void, updateCommissioningNetworkCredentials) (JNIEnv * env, jobject self, jlong handle, jobject networkCredentials) { ChipLogProgress(Controller, "updateCommissioningNetworkCredentials() called"); chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); CommissioningParameters commissioningParams = wrapper->GetAutoCommissioner()->GetCommissioningParameters(); CHIP_ERROR err = wrapper->ApplyNetworkCredentials(commissioningParams, networkCredentials); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "ApplyNetworkCredentials failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } err = wrapper->GetAutoCommissioner()->SetCommissioningParameters(commissioningParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "SetCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } // Only invoke NetworkCredentialsReady when called in response to NetworkScan result if (wrapper->Controller()->GetCommissioningStage() == CommissioningStage::kNeedsNetworkCreds) { err = wrapper->Controller()->NetworkCredentialsReady(); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "NetworkCredentialsReady failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } } JNI_METHOD(void, updateCommissioningICDRegistrationInfo) (JNIEnv * env, jobject self, jlong handle, jobject icdRegistrationInfo) { ChipLogProgress(Controller, "updateCommissioningICDRegistrationInfo() called"); chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); CommissioningParameters commissioningParams = wrapper->GetAutoCommissioner()->GetCommissioningParameters(); CHIP_ERROR err = wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "ApplyICDRegistrationInfo failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } err = wrapper->GetAutoCommissioner()->SetCommissioningParameters(commissioningParams); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "SetCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } // Only invoke ICDRegistrationInfoReady when called in ICDRegistartionInfo stage. if (wrapper->Controller()->GetCommissioningStage() == CommissioningStage::kICDGetRegistrationInfo) { err = wrapper->Controller()->ICDRegistrationInfoReady(); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "ICDRegistrationInfoReady failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } } jint GetCalendarFieldID(JNIEnv * env, const char * method) { jclass calendarCls = env->FindClass("java/util/Calendar"); jfieldID fieldID = env->GetStaticFieldID(calendarCls, method, "I"); return env->GetStaticIntField(calendarCls, fieldID); } CHIP_ERROR GetEpochTime(JNIEnv * env, jobject calendar, uint32_t & epochTime) { using namespace ASN1; ASN1UniversalTime universalTime; jmethodID getMethod = nullptr; jint yearID = GetCalendarFieldID(env, "YEAR"); jint monthID = GetCalendarFieldID(env, "MONTH"); jint dayID = GetCalendarFieldID(env, "DAY_OF_MONTH"); jint hourID = GetCalendarFieldID(env, "HOUR_OF_DAY"); jint minuteID = GetCalendarFieldID(env, "MINUTE"); jint secondID = GetCalendarFieldID(env, "SECOND"); if (calendar == nullptr) { return CHIP_ERROR_INVALID_ARGUMENT; } ReturnErrorOnFailure(JniReferences::GetInstance().FindMethod(env, calendar, "get", "(I)I", &getMethod)); universalTime.Year = static_cast(env->CallIntMethod(calendar, getMethod, yearID)); // The first month of the year in the Gregorian and Julian calendars is JANUARY which is 0. See detailed in // https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#MONTH universalTime.Month = static_cast(static_cast(env->CallIntMethod(calendar, getMethod, monthID)) + 1u); universalTime.Day = static_cast(env->CallIntMethod(calendar, getMethod, dayID)); universalTime.Hour = static_cast(env->CallIntMethod(calendar, getMethod, hourID)); universalTime.Minute = static_cast(env->CallIntMethod(calendar, getMethod, minuteID)); universalTime.Second = static_cast(env->CallIntMethod(calendar, getMethod, secondID)); ReturnErrorOnFailure(ASN1ToChipEpochTime(universalTime, epochTime)); return CHIP_NO_ERROR; } JNI_METHOD(jbyteArray, createRootCertificate) (JNIEnv * env, jclass clazz, jobject jKeypair, jlong issuerId, jobject fabricId, jobject validityStart, jobject validityEnd) { #ifdef JAVA_MATTER_CONTROLLER_TEST return nullptr; #else CHIP_ERROR err = CHIP_NO_ERROR; uint32_t allocatedCertLength = chip::Credentials::kMaxDERCertLength; chip::Platform::ScopedMemoryBuffer outBuf; jbyteArray outRcac = nullptr; CHIPP256KeypairBridge keypair; Optional fabric = Optional(); VerifyOrExit(outBuf.Alloc(allocatedCertLength), err = CHIP_ERROR_NO_MEMORY); keypair.SetDelegate(jKeypair); err = keypair.Initialize(Crypto::ECPKeyTarget::ECDSA); SuccessOrExit(err); if (fabricId != nullptr) { jlong jfabricId = chip::JniReferences::GetInstance().LongToPrimitive(fabricId); fabric = MakeOptional(static_cast(jfabricId)); } { MutableByteSpan rcac(outBuf.Get(), allocatedCertLength); uint32_t start; uint32_t end; err = GetEpochTime(env, validityStart, start); SuccessOrExit(err); err = GetEpochTime(env, validityEnd, end); SuccessOrExit(err); err = AndroidOperationalCredentialsIssuer::GenerateRootCertificate(keypair, static_cast(issuerId), fabric, start, end, rcac); SuccessOrExit(err); err = JniReferences::GetInstance().N2J_ByteArray(env, rcac.data(), static_cast(rcac.size()), outRcac); SuccessOrExit(err); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to create Root Certificate. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return outRcac; #endif } JNI_METHOD(jbyteArray, createIntermediateCertificate) (JNIEnv * env, jclass clazz, jobject rootKeypair, jbyteArray rootCertificate, jbyteArray intermediatePublicKey, jlong issuerId, jobject fabricId, jobject validityStart, jobject validityEnd) { #ifdef JAVA_MATTER_CONTROLLER_TEST return nullptr; #else CHIP_ERROR err = CHIP_NO_ERROR; uint32_t allocatedCertLength = chip::Credentials::kMaxDERCertLength; chip::Platform::ScopedMemoryBuffer outBuf; jbyteArray outIcac = nullptr; CHIPP256KeypairBridge keypair; Optional fabric = Optional(); chip::JniByteArray jniRcac(env, rootCertificate); chip::JniByteArray jnipublicKey(env, intermediatePublicKey); Credentials::P256PublicKeySpan publicKeySpan(reinterpret_cast(jnipublicKey.data())); Crypto::P256PublicKey publicKey{ publicKeySpan }; VerifyOrExit(outBuf.Alloc(allocatedCertLength), err = CHIP_ERROR_NO_MEMORY); keypair.SetDelegate(rootKeypair); err = keypair.Initialize(Crypto::ECPKeyTarget::ECDSA); SuccessOrExit(err); if (fabricId != nullptr) { jlong jfabricId = chip::JniReferences::GetInstance().LongToPrimitive(fabricId); fabric = MakeOptional(static_cast(jfabricId)); } { MutableByteSpan icac(outBuf.Get(), allocatedCertLength); uint32_t start; uint32_t end; err = GetEpochTime(env, validityStart, start); SuccessOrExit(err); err = GetEpochTime(env, validityEnd, end); SuccessOrExit(err); err = AndroidOperationalCredentialsIssuer::GenerateIntermediateCertificate( keypair, jniRcac.byteSpan(), publicKey, static_cast(issuerId), fabric, start, end, icac); SuccessOrExit(err); ChipLogByteSpan(Controller, icac); err = JniReferences::GetInstance().N2J_ByteArray(env, icac.data(), static_cast(icac.size()), outIcac); SuccessOrExit(err); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to create Intermediate Certificate. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return outIcac; #endif } JNI_METHOD(jbyteArray, createOperationalCertificate) (JNIEnv * env, jclass clazz, jobject signingKeypair, jbyteArray signingCertificate, jbyteArray operationalPublicKey, jlong fabricId, jlong nodeId, jobject caseAuthenticatedTags, jobject validityStart, jobject validityEnd) { #ifdef JAVA_MATTER_CONTROLLER_TEST return nullptr; #else CHIP_ERROR err = CHIP_NO_ERROR; uint32_t allocatedCertLength = chip::Credentials::kMaxDERCertLength; chip::Platform::ScopedMemoryBuffer outBuf; jbyteArray outNoc = nullptr; CHIPP256KeypairBridge keypair; chip::JniByteArray jniCert(env, signingCertificate); chip::JniByteArray jnipublicKey(env, operationalPublicKey); Credentials::P256PublicKeySpan publicKeySpan(reinterpret_cast(jnipublicKey.data())); Crypto::P256PublicKey publicKey{ publicKeySpan }; chip::CATValues cats = chip::kUndefinedCATs; if (caseAuthenticatedTags != nullptr) { jint size; JniReferences::GetInstance().GetListSize(caseAuthenticatedTags, size); VerifyOrExit(static_cast(size) <= chip::kMaxSubjectCATAttributeCount, err = CHIP_ERROR_INVALID_ARGUMENT); for (jint i = 0; i < size; i++) { jobject cat = nullptr; JniReferences::GetInstance().GetListItem(caseAuthenticatedTags, i, cat); VerifyOrExit(cat != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); cats.values[i] = static_cast(JniReferences::GetInstance().IntegerToPrimitive(cat)); } } VerifyOrExit(outBuf.Alloc(allocatedCertLength), err = CHIP_ERROR_NO_MEMORY); keypair.SetDelegate(signingKeypair); err = keypair.Initialize(Crypto::ECPKeyTarget::ECDSA); SuccessOrExit(err); { MutableByteSpan noc(outBuf.Get(), allocatedCertLength); uint32_t start; uint32_t end; err = GetEpochTime(env, validityStart, start); SuccessOrExit(err); err = GetEpochTime(env, validityEnd, end); SuccessOrExit(err); err = AndroidOperationalCredentialsIssuer::GenerateOperationalCertificate( keypair, jniCert.byteSpan(), publicKey, static_cast(fabricId), static_cast(nodeId), cats, start, end, noc); SuccessOrExit(err); ChipLogByteSpan(Controller, noc); err = JniReferences::GetInstance().N2J_ByteArray(env, noc.data(), static_cast(noc.size()), outNoc); SuccessOrExit(err); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to create Intermediate Certificate. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return outNoc; #endif } JNI_METHOD(jbyteArray, publicKeyFromCSR) (JNIEnv * env, jclass clazz, jbyteArray certificateSigningRequest) { jbyteArray outJbytes = nullptr; chip::JniByteArray jniCsr(env, certificateSigningRequest); P256PublicKey publicKey; CHIP_ERROR err = VerifyCertificateSigningRequest(jniCsr.byteSpan().data(), jniCsr.byteSpan().size(), publicKey); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "publicKeyFromCSR: %" CHIP_ERROR_FORMAT, err.Format()); return nullptr; } err = JniReferences::GetInstance().N2J_ByteArray(env, publicKey.Bytes(), static_cast(publicKey.Length()), outJbytes); SuccessOrExit(err); exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to publicKeyFromCSR. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return outJbytes; } JNI_METHOD(jbyteArray, convertX509CertToMatterCert) (JNIEnv * env, jobject self, jbyteArray x509Cert) { chip::DeviceLayer::StackLock lock; uint32_t allocatedCertLength = chip::Credentials::kMaxCHIPCertLength; chip::Platform::ScopedMemoryBuffer outBuf; jbyteArray outJbytes = nullptr; JniByteArray x509CertBytes(env, x509Cert); CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(outBuf.Alloc(allocatedCertLength), err = CHIP_ERROR_NO_MEMORY); { MutableByteSpan outBytes(outBuf.Get(), allocatedCertLength); err = chip::Credentials::ConvertX509CertToChipCert(x509CertBytes.byteSpan(), outBytes); SuccessOrExit(err); VerifyOrExit(chip::CanCastTo(outBytes.size()), err = CHIP_ERROR_INTERNAL); err = JniReferences::GetInstance().N2J_ByteArray(env, outBytes.data(), static_cast(outBytes.size()), outJbytes); SuccessOrExit(err); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to convert X509 cert to CHIP cert. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return outJbytes; } JNI_METHOD(void, unpairDevice)(JNIEnv * env, jobject self, jlong handle, jlong deviceId) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "unpairDevice() called with device ID"); err = wrapper->Controller()->UnpairDevice(static_cast(deviceId)); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to unpair the device."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, unpairDeviceCallback)(JNIEnv * env, jobject self, jlong handle, jlong deviceId, jobject callback) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "unpairDeviceCallback() called with device ID and callback object"); err = AndroidCurrentFabricRemover::RemoveCurrentFabric(wrapper->Controller(), static_cast(deviceId), callback); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to unpair the device."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(void, stopDevicePairing)(JNIEnv * env, jobject self, jlong handle, jlong deviceId) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "stopDevicePairing() called with device ID"); err = wrapper->Controller()->StopPairing(static_cast(deviceId)); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to unpair the device."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(jlong, getDeviceBeingCommissionedPointer)(JNIEnv * env, jobject self, jlong handle, jlong nodeId) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); CommissioneeDeviceProxy * commissioneeDevice = nullptr; err = wrapper->Controller()->GetDeviceBeingCommissioned(static_cast(nodeId), &commissioneeDevice); if (commissioneeDevice == nullptr) { ChipLogError(Controller, "Commissionee device was nullptr"); err = CHIP_ERROR_INCORRECT_STATE; } if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to get commissionee device: %s", ErrorStr(err)); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return 0; } return reinterpret_cast(commissioneeDevice); } JNI_METHOD(void, getConnectedDevicePointer)(JNIEnv * env, jobject self, jlong handle, jlong nodeId, jlong callbackHandle) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); GetConnectedDeviceCallback * connectedDeviceCallback = reinterpret_cast(callbackHandle); VerifyOrExit(connectedDeviceCallback != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); err = wrapper->Controller()->GetConnectedDevice(static_cast(nodeId), &connectedDeviceCallback->mOnSuccess, &connectedDeviceCallback->mOnFailure); exit: if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "GetConnectedDevice failed: %" CHIP_ERROR_FORMAT, err.Format()); OperationalSessionSetup::ConnectionFailureInfo failureInfo( chip::ScopedNodeId(static_cast(nodeId), wrapper->Controller()->GetFabricIndex()), err, SessionEstablishmentStage::kUnknown); connectedDeviceCallback->mOnFailure.mCall(&connectedDeviceCallback->mOnFailure.mContext, failureInfo); } } JNI_METHOD(void, releaseOperationalDevicePointer)(JNIEnv * env, jobject self, jlong devicePtr) { chip::DeviceLayer::StackLock lock; OperationalDeviceProxy * device = reinterpret_cast(devicePtr); if (device != nullptr) { delete device; } } JNI_METHOD(jlong, getGroupDevicePointer)(JNIEnv * env, jobject self, jlong handle, jint groupId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, 0, ChipLogError(Controller, "wrapper is null")); GroupDeviceProxy * device = new GroupDeviceProxy(static_cast(groupId), wrapper->Controller()->GetFabricIndex(), wrapper->Controller()->ExchangeMgr()); if (device == nullptr) { CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; ChipLogError(Controller, "GroupDeviceProxy handle is nullptr: %s", ErrorStr(err)); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return 0; } return reinterpret_cast(device); } JNI_METHOD(void, releaseGroupDevicePointer)(JNIEnv * env, jobject self, jlong devicePtr) { chip::DeviceLayer::StackLock lock; GroupDeviceProxy * device = reinterpret_cast(devicePtr); if (device != nullptr) { delete device; } } JNI_METHOD(jobject, getAvailableGroupIds)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, nullptr, ChipLogError(Controller, "wrapper is null")); CHIP_ERROR err = CHIP_NO_ERROR; chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); auto it = groupDataProvider->IterateGroupInfo(wrapper->Controller()->GetFabricIndex()); jobject groupIds; err = chip::JniReferences::GetInstance().CreateArrayList(groupIds); chip::Credentials::GroupDataProvider::GroupInfo group; if (it) { while (it->Next(group)) { jobject jGroupId; chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", static_cast(group.group_id), jGroupId); chip::JniReferences::GetInstance().AddToList(groupIds, jGroupId); } } return groupIds; } JNI_METHOD(jstring, getGroupName)(JNIEnv * env, jobject self, jlong handle, jint jGroupId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, nullptr, ChipLogError(Controller, "wrapper is null")); chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); auto it = groupDataProvider->IterateGroupInfo(wrapper->Controller()->GetFabricIndex()); GroupId groupId = static_cast(jGroupId); chip::Credentials::GroupDataProvider::GroupInfo group; if (it) { while (it->Next(group)) { if (group.group_id == groupId) { return env->NewStringUTF(group.name); } } } return nullptr; } JNI_METHOD(jobject, findKeySetId)(JNIEnv * env, jobject self, jlong handle, jint jGroupId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, nullptr, ChipLogError(Controller, "wrapper is null")); chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); auto iter = groupDataProvider->IterateGroupKeys(wrapper->Controller()->GetFabricIndex()); chip::Credentials::GroupDataProvider::GroupKey groupKey; GroupId groupId = static_cast(jGroupId); jobject wrapperKeyId; if (iter) { while (iter->Next(groupKey)) { if (groupKey.group_id == groupId) { jobject jKeyId; chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", static_cast(groupKey.keyset_id), jKeyId); chip::JniReferences::GetInstance().CreateOptional(jKeyId, wrapperKeyId); iter->Release(); return wrapperKeyId; } } iter->Release(); } chip::JniReferences::GetInstance().CreateOptional(nullptr, wrapperKeyId); return wrapperKeyId; } JNI_METHOD(jboolean, addGroup)(JNIEnv * env, jobject self, jlong handle, jint jGroupId, jstring groupName) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, JNI_FALSE, ChipLogError(Controller, "wrapper is null")); chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); chip::Credentials::GroupDataProvider::GroupInfo group; chip::JniUtfString jniGroupName(env, groupName); group.SetName(jniGroupName.charSpan()); group.group_id = static_cast(jGroupId); CHIP_ERROR err = groupDataProvider->SetGroupInfo(wrapper->Controller()->GetFabricIndex(), group); return err == CHIP_NO_ERROR ? JNI_TRUE : JNI_FALSE; } JNI_METHOD(jboolean, removeGroup)(JNIEnv * env, jobject self, jlong handle, jint jGroupId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, JNI_FALSE, ChipLogError(Controller, "wrapper is null")); chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); CHIP_ERROR err = groupDataProvider->RemoveGroupInfo(wrapper->Controller()->GetFabricIndex(), static_cast(jGroupId)); return err == CHIP_NO_ERROR ? JNI_TRUE : JNI_FALSE; } JNI_METHOD(jobject, getKeySetIds)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, nullptr, ChipLogError(Controller, "wrapper is null")); CHIP_ERROR err = CHIP_NO_ERROR; chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); auto it = groupDataProvider->IterateKeySets(wrapper->Controller()->GetFabricIndex()); jobject keySetIds; err = chip::JniReferences::GetInstance().CreateArrayList(keySetIds); chip::Credentials::GroupDataProvider::KeySet keySet; if (it) { while (it->Next(keySet)) { jobject jKeySetId; chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", static_cast(keySet.keyset_id), jKeySetId); chip::JniReferences::GetInstance().AddToList(keySetIds, jKeySetId); } it->Release(); } return keySetIds; } JNI_METHOD(jobject, getKeySecurityPolicy)(JNIEnv * env, jobject self, jlong handle, int jKeySetId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, nullptr, ChipLogError(Controller, "wrapper is null")); chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); auto it = groupDataProvider->IterateKeySets(wrapper->Controller()->GetFabricIndex()); chip::Credentials::GroupDataProvider::KeySet keySet; uint16_t keySetId = static_cast(jKeySetId); jobject wrapperKeyPolicy; if (it) { while (it->Next(keySet)) { if (keySet.keyset_id == keySetId) { jobject jKeyPolicy; chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", static_cast(keySet.policy), jKeyPolicy); chip::JniReferences::GetInstance().CreateOptional(jKeyPolicy, wrapperKeyPolicy); it->Release(); return wrapperKeyPolicy; } } it->Release(); } chip::JniReferences::GetInstance().CreateOptional(nullptr, wrapperKeyPolicy); return wrapperKeyPolicy; } JNI_METHOD(jboolean, bindKeySet)(JNIEnv * env, jobject self, jlong handle, jint jGroupId, jint jKeySetId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, JNI_FALSE, ChipLogError(Controller, "wrapper is null")); chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); auto iter = groupDataProvider->IterateGroupKeys(wrapper->Controller()->GetFabricIndex()); size_t current_count = iter->Count(); iter->Release(); CHIP_ERROR err = groupDataProvider->SetGroupKeyAt( wrapper->Controller()->GetFabricIndex(), current_count, chip::Credentials::GroupDataProvider::GroupKey(static_cast(jGroupId), static_cast(jKeySetId))); return err == CHIP_NO_ERROR ? JNI_TRUE : JNI_FALSE; } JNI_METHOD(jboolean, unbindKeySet)(JNIEnv * env, jobject self, jlong handle, jint jGroupId, jint jKeySetId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, JNI_FALSE, ChipLogError(Controller, "wrapper is null")); size_t index = 0; chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); auto iter = groupDataProvider->IterateGroupKeys(wrapper->Controller()->GetFabricIndex()); size_t maxCount = iter->Count(); chip::Credentials::GroupDataProvider::GroupKey groupKey; GroupId groupId = static_cast(jGroupId); uint16_t keysetId = static_cast(jKeySetId); while (iter->Next(groupKey)) { if (groupKey.group_id == groupId && groupKey.keyset_id == keysetId) { break; } index++; } iter->Release(); if (index >= maxCount) { return JNI_FALSE; } CHIP_ERROR err = groupDataProvider->RemoveGroupKeyAt(wrapper->Controller()->GetFabricIndex(), index); return err == CHIP_NO_ERROR ? JNI_TRUE : JNI_FALSE; } JNI_METHOD(jboolean, addKeySet) (JNIEnv * env, jobject self, jlong handle, jint jKeySetId, jint jKeyPolicy, jlong validityTime, jbyteArray epochKey) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, JNI_FALSE, ChipLogError(Controller, "wrapper is null")); chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); uint8_t compressed_fabric_id[sizeof(chip::FabricId)]; chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id); VerifyOrReturnValue(wrapper->Controller()->GetCompressedFabricIdBytes(compressed_fabric_id_span) == CHIP_NO_ERROR, JNI_FALSE); chip::Credentials::GroupDataProvider::SecurityPolicy keyPolicy = static_cast(jKeyPolicy); chip::JniByteArray jniEpochKey(env, epochKey); size_t epochKeySize = static_cast(jniEpochKey.size()); if ((keyPolicy != chip::Credentials::GroupDataProvider::SecurityPolicy::kCacheAndSync && keyPolicy != chip::Credentials::GroupDataProvider::SecurityPolicy::kTrustFirst) || epochKeySize != chip::Credentials::GroupDataProvider::EpochKey::kLengthBytes) { return JNI_FALSE; } chip::Credentials::GroupDataProvider::KeySet keySet(static_cast(jKeySetId), keyPolicy, 1); chip::Credentials::GroupDataProvider::EpochKey epoch_key; epoch_key.start_time = static_cast(validityTime); memcpy(epoch_key.key, jniEpochKey.byteSpan().data(), chip::Credentials::GroupDataProvider::EpochKey::kLengthBytes); memcpy(keySet.epoch_keys, &epoch_key, sizeof(chip::Credentials::GroupDataProvider::EpochKey)); VerifyOrReturnValue(groupDataProvider->SetKeySet(wrapper->Controller()->GetFabricIndex(), compressed_fabric_id_span, keySet) == CHIP_NO_ERROR, JNI_FALSE); return JNI_TRUE; } JNI_METHOD(jboolean, removeKeySet)(JNIEnv * env, jobject self, jlong handle, jint jKeySetId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturnValue(wrapper != nullptr, JNI_FALSE, ChipLogError(Controller, "wrapper is null")); CHIP_ERROR err = CHIP_NO_ERROR; chip::Credentials::GroupDataProvider * groupDataProvider = chip::Credentials::GetGroupDataProvider(); size_t index = 0; auto iter = groupDataProvider->IterateGroupKeys(wrapper->Controller()->GetFabricIndex()); uint16_t keysetId = static_cast(jKeySetId); chip::Credentials::GroupDataProvider::GroupKey groupKey; if (iter) { while (iter->Next(groupKey)) { if (groupKey.keyset_id == keysetId) { err = groupDataProvider->RemoveGroupKeyAt(wrapper->Controller()->GetFabricIndex(), index); if (err != CHIP_NO_ERROR) { break; } } index++; } iter->Release(); if (err == CHIP_NO_ERROR) { err = groupDataProvider->RemoveKeySet(wrapper->Controller()->GetFabricIndex(), keysetId); } return err == CHIP_NO_ERROR ? JNI_TRUE : JNI_FALSE; } return JNI_FALSE; } JNI_METHOD(jint, getFabricIndex)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); return wrapper->Controller()->GetFabricIndex(); } JNI_METHOD(jstring, getIpAddress)(JNIEnv * env, jobject self, jlong handle, jlong deviceId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); chip::Inet::IPAddress addr; uint16_t port; char addrStr[50]; CHIP_ERROR err = wrapper->Controller()->GetPeerAddressAndPort(static_cast(deviceId), addr, port); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to get device address."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return nullptr; } addr.ToString(addrStr); return env->NewStringUTF(addrStr); } JNI_METHOD(jlong, generateCompressedFabricId) (JNIEnv * env, jobject self, jbyteArray rcac, jbyteArray noc) { chip::DeviceLayer::StackLock lock; CompressedFabricId compressedFabricId; FabricId fabricId; NodeId nodeId; CHIP_ERROR err = CHIP_NO_ERROR; chip::JniByteArray jniRcac(env, rcac); chip::JniByteArray jniNoc(env, noc); err = ExtractNodeIdFabricIdCompressedFabricIdFromOpCerts(jniRcac.byteSpan(), jniNoc.byteSpan(), compressedFabricId, fabricId, nodeId); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to extract compressed fabric ID."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return static_cast(compressedFabricId); } JNI_METHOD(jobject, getNetworkLocation)(JNIEnv * env, jobject self, jlong handle, jlong deviceId) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); Transport::PeerAddress addr; jobject networkLocation = nullptr; char addrStr[50]; CHIP_ERROR err = wrapper->Controller()->GetPeerAddress(static_cast(deviceId), addr); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to get device address."); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return nullptr; } addr.GetIPAddress().ToString(addrStr); err = N2J_NetworkLocation(env, env->NewStringUTF(addrStr), static_cast(addr.GetPort()), static_cast(addr.GetInterface().GetPlatformInterface()), networkLocation); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to create NetworkLocation"); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return networkLocation; } JNI_METHOD(jlong, getCompressedFabricId)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); return static_cast(wrapper->Controller()->GetCompressedFabricId()); } JNI_METHOD(jlong, getControllerNodeId)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); return static_cast(wrapper->Controller()->GetNodeId()); } JNI_METHOD(void, discoverCommissionableNodes)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); chip::Dnssd::DiscoveryFilter filter(Dnssd::DiscoveryFilterType::kNone, (uint64_t) 0); CHIP_ERROR err = wrapper->Controller()->DiscoverCommissionableNodes(filter); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to discoverCommissionableNodes"); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } JNI_METHOD(jobject, getDiscoveredDevice)(JNIEnv * env, jobject self, jlong handle, jint idx) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); const Dnssd::CommissionNodeData * data = wrapper->Controller()->GetDiscoveredDevice(idx); if (data == nullptr) { ChipLogError(Controller, "GetDiscoveredDevice - not found"); return nullptr; } jclass discoveredDeviceCls = env->FindClass("chip/devicecontroller/DiscoveredDevice"); jmethodID constructor = env->GetMethodID(discoveredDeviceCls, "", "()V"); jfieldID discrminatorID = env->GetFieldID(discoveredDeviceCls, "discriminator", "J"); jfieldID ipAddressID = env->GetFieldID(discoveredDeviceCls, "ipAddress", "Ljava/lang/String;"); jfieldID portID = env->GetFieldID(discoveredDeviceCls, "port", "I"); jfieldID deviceTypeID = env->GetFieldID(discoveredDeviceCls, "deviceType", "J"); jfieldID vendorIdID = env->GetFieldID(discoveredDeviceCls, "vendorId", "I"); jfieldID productIdID = env->GetFieldID(discoveredDeviceCls, "productId", "I"); jfieldID rotatingIdID = env->GetFieldID(discoveredDeviceCls, "rotatingId", "[B"); jfieldID instanceNameID = env->GetFieldID(discoveredDeviceCls, "instanceName", "Ljava/lang/String;"); jfieldID deviceNameID = env->GetFieldID(discoveredDeviceCls, "deviceName", "Ljava/lang/String;"); jfieldID pairingInstructionID = env->GetFieldID(discoveredDeviceCls, "pairingInstruction", "Ljava/lang/String;"); jmethodID setCommissioningModeID = env->GetMethodID(discoveredDeviceCls, "setCommissioningMode", "(I)V"); jmethodID setPairingHintID = env->GetMethodID(discoveredDeviceCls, "setPairingHint", "(I)V"); jobject discoveredObj = env->NewObject(discoveredDeviceCls, constructor); env->SetLongField(discoveredObj, discrminatorID, data->longDiscriminator); char ipAddress[100]; data->ipAddress[0].ToString(ipAddress, 100); jstring jniipAdress = env->NewStringUTF(ipAddress); env->SetObjectField(discoveredObj, ipAddressID, jniipAdress); env->SetIntField(discoveredObj, portID, static_cast(data->port)); env->SetLongField(discoveredObj, deviceTypeID, static_cast(data->deviceType)); env->SetIntField(discoveredObj, vendorIdID, static_cast(data->vendorId)); env->SetIntField(discoveredObj, productIdID, static_cast(data->productId)); jbyteArray jRotatingId; CHIP_ERROR err = JniReferences::GetInstance().N2J_ByteArray(env, data->rotatingId, static_cast(data->rotatingIdLen), jRotatingId); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "jRotatingId N2J_ByteArray error : %" CHIP_ERROR_FORMAT, err.Format()); return nullptr; } env->SetObjectField(discoveredObj, rotatingIdID, static_cast(jRotatingId)); env->SetObjectField(discoveredObj, instanceNameID, env->NewStringUTF(data->instanceName)); env->SetObjectField(discoveredObj, deviceNameID, env->NewStringUTF(data->deviceName)); env->SetObjectField(discoveredObj, pairingInstructionID, env->NewStringUTF(data->pairingInstruction)); env->CallVoidMethod(discoveredObj, setCommissioningModeID, static_cast(data->commissioningMode)); env->CallVoidMethod(discoveredObj, setPairingHintID, static_cast(data->pairingHint)); return discoveredObj; } JNI_METHOD(jboolean, openPairingWindow)(JNIEnv * env, jobject self, jlong handle, jlong devicePtr, jint duration) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; DeviceProxy * chipDevice = reinterpret_cast(devicePtr); if (chipDevice == nullptr) { ChipLogProgress(Controller, "Could not cast device pointer to Device object"); return false; } AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); err = AutoCommissioningWindowOpener::OpenBasicCommissioningWindow(wrapper->Controller(), chipDevice->GetDeviceId(), System::Clock::Seconds16(duration)); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "OpenPairingWindow failed: %" CHIP_ERROR_FORMAT, err.Format()); return false; } return true; } JNI_METHOD(jboolean, openPairingWindowWithPIN) (JNIEnv * env, jobject self, jlong handle, jlong devicePtr, jint duration, jlong iteration, jint discriminator, jobject setupPinCode) { VerifyOrReturnValue(chip::CanCastTo(iteration), false); chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; DeviceProxy * chipDevice = reinterpret_cast(devicePtr); if (chipDevice == nullptr) { ChipLogProgress(Controller, "Could not cast device pointer to Device object"); return false; } AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); Optional pinCode = Optional(); if (setupPinCode != nullptr) { jlong jsetupPinCode = chip::JniReferences::GetInstance().LongToPrimitive(setupPinCode); pinCode = MakeOptional(static_cast(jsetupPinCode)); } chip::SetupPayload setupPayload; err = AutoCommissioningWindowOpener::OpenCommissioningWindow( wrapper->Controller(), chipDevice->GetDeviceId(), System::Clock::Seconds16(duration), static_cast(iteration), static_cast(discriminator), pinCode, NullOptional, setupPayload); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "OpenPairingWindow failed: %" CHIP_ERROR_FORMAT, err.Format()); return false; } return true; } JNI_METHOD(jboolean, openPairingWindowCallback) (JNIEnv * env, jobject self, jlong handle, jlong devicePtr, jint duration, jobject jcallback) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; DeviceProxy * chipDevice = reinterpret_cast(devicePtr); if (chipDevice == nullptr) { ChipLogProgress(Controller, "Could not cast device pointer to Device object"); return false; } AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); err = AndroidCommissioningWindowOpener::OpenBasicCommissioningWindow(wrapper->Controller(), chipDevice->GetDeviceId(), System::Clock::Seconds16(duration), jcallback); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "OpenPairingWindow failed: %" CHIP_ERROR_FORMAT, err.Format()); return false; } return true; } JNI_METHOD(jboolean, openPairingWindowWithPINCallback) (JNIEnv * env, jobject self, jlong handle, jlong devicePtr, jint duration, jlong iteration, jint discriminator, jobject setupPinCode, jobject jcallback) { VerifyOrReturnValue(chip::CanCastTo(iteration), false); chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; DeviceProxy * chipDevice = reinterpret_cast(devicePtr); if (chipDevice == nullptr) { ChipLogProgress(Controller, "Could not cast device pointer to Device object"); return false; } AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); Optional pinCode = Optional(); if (setupPinCode != nullptr) { jlong jsetupPinCode = chip::JniReferences::GetInstance().LongToPrimitive(setupPinCode); pinCode = MakeOptional(static_cast(jsetupPinCode)); } chip::SetupPayload setupPayload; err = AndroidCommissioningWindowOpener::OpenCommissioningWindow( wrapper->Controller(), chipDevice->GetDeviceId(), System::Clock::Seconds16(duration), static_cast(iteration), static_cast(discriminator), pinCode, NullOptional, jcallback, setupPayload); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "OpenPairingWindow failed: %" CHIP_ERROR_FORMAT, err.Format()); return false; } return true; } JNI_METHOD(void, shutdownCommissioning) (JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; // Stop the IO thread, so that the controller can be safely shut down. StopIOThread(); AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); wrapper->Shutdown(); } JNI_METHOD(jbyteArray, getAttestationChallenge) (JNIEnv * env, jobject self, jlong handle, jlong devicePtr) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; ByteSpan attestationChallenge; jbyteArray attestationChallengeJbytes = nullptr; DeviceProxy * chipDevice = reinterpret_cast(devicePtr); if (chipDevice == nullptr) { ChipLogProgress(Controller, "Could not cast device pointer to Device object"); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INCORRECT_STATE); return nullptr; } err = chipDevice->GetAttestationChallenge(attestationChallenge); SuccessOrExit(err); VerifyOrExit(attestationChallenge.size() == 16, err = CHIP_ERROR_INVALID_ARGUMENT); err = JniReferences::GetInstance().N2J_ByteArray(env, attestationChallenge.data(), static_cast(attestationChallenge.size()), attestationChallengeJbytes); SuccessOrExit(err); exit: if (err != CHIP_NO_ERROR) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return attestationChallengeJbytes; } JNI_METHOD(void, deleteDeviceController)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); ChipLogProgress(Controller, "deleteDeviceController() called"); if (wrapper != nullptr) { delete wrapper; } } JNI_METHOD(jobject, computePaseVerifier) (JNIEnv * env, jobject self, jlong handle, jlong devicePtr, jlong setupPincode, jlong iterations, jbyteArray salt) { chip::DeviceLayer::StackLock lock; CHIP_ERROR err = CHIP_NO_ERROR; jobject params; jbyteArray verifierBytes; Spake2pVerifier verifier; Spake2pVerifierSerialized serializedVerifier; MutableByteSpan serializedVerifierSpan(serializedVerifier); JniByteArray jniSalt(env, salt); ChipLogProgress(Controller, "computePaseVerifier() called"); AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrExit(chip::CanCastTo(iterations), err = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(chip::CanCastTo(setupPincode), err = CHIP_ERROR_INVALID_ARGUMENT); err = wrapper->Controller()->ComputePASEVerifier(static_cast(iterations), static_cast(setupPincode), jniSalt.byteSpan(), verifier); SuccessOrExit(err); err = verifier.Serialize(serializedVerifierSpan); SuccessOrExit(err); err = JniReferences::GetInstance().N2J_ByteArray(env, serializedVerifier, kSpake2p_VerifierSerialized_Length, verifierBytes); SuccessOrExit(err); err = N2J_PaseVerifierParams(env, setupPincode, verifierBytes, params); SuccessOrExit(err); return params; exit: if (err != CHIP_NO_ERROR) { JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return nullptr; } JNI_METHOD(jbyteArray, validateAndExtractCSR)(JNIEnv * env, jclass clazz, jbyteArray jCsrElements, jbyteArray jCsrNonce) { chip::JniByteArray csrElements(env, jCsrElements); chip::JniByteArray csrNonce(env, jCsrNonce); chip::ByteSpan csrSpan; chip::ByteSpan csrNonceSpan; chip::ByteSpan vendor_reserved1, vendor_reserved2, vendor_reserved3; CHIP_ERROR err = chip::Credentials::DeconstructNOCSRElements(csrElements.byteSpan(), csrSpan, csrNonceSpan, vendor_reserved1, vendor_reserved2, vendor_reserved3); VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogError(Controller, "CsrElement decoding error: %" CHIP_ERROR_FORMAT, err.Format())); VerifyOrReturnValue(csrNonceSpan.size() == Controller::kCSRNonceLength, nullptr, ChipLogError(Controller, "csrNonce size is invalid")); // Verify that Nonce matches with what we sent VerifyOrReturnValue(csrNonceSpan.data_equal(csrNonce.byteSpan()), nullptr, ChipLogError(Controller, "csrNonce is not matched!")); jbyteArray javaCsr; chip::JniReferences::GetInstance().N2J_ByteArray(chip::JniReferences::GetInstance().GetEnvForCurrentThread(), csrSpan.data(), static_cast(csrSpan.size()), javaCsr); return javaCsr; } JNI_METHOD(void, startDnssd)(JNIEnv * env, jobject self, jlong handle) { ChipLogProgress(Controller, "startDnssd() called"); chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturn(wrapper != nullptr, ChipLogError(Controller, "AndroidDeviceControllerWrapper::FromJNIHandle in startDnssd fails!")); wrapper->StartDnssd(); } JNI_METHOD(void, stopDnssd)(JNIEnv * env, jobject self, jlong handle) { ChipLogProgress(Controller, "stopDnssd() called"); chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); VerifyOrReturn(wrapper != nullptr, ChipLogError(Controller, "AndroidDeviceControllerWrapper::FromJNIHandle in stopDnssd fails!")); wrapper->StopDnssd(); } void * IOThreadMain(void * arg) { JNIEnv * env; JavaVMAttachArgs attachArgs; // Attach the IO thread to the JVM as a daemon thread. // This allows the JVM to shutdown without waiting for this thread to exit. attachArgs.version = JNI_VERSION_1_6; attachArgs.name = (char *) "CHIP Device Controller IO Thread"; attachArgs.group = nullptr; #ifdef __ANDROID__ sJVM->AttachCurrentThreadAsDaemon(&env, (void *) &attachArgs); #else sJVM->AttachCurrentThreadAsDaemon((void **) &env, (void *) &attachArgs); #endif ChipLogProgress(Controller, "IO thread starting"); chip::DeviceLayer::PlatformMgr().RunEventLoop(); ChipLogProgress(Controller, "IO thread ending"); // Detach the thread from the JVM. sJVM->DetachCurrentThread(); return nullptr; } // NOTE: This function SHALL be called with the stack lock held. CHIP_ERROR StopIOThread() { if (sIOThread != PTHREAD_NULL) { ChipLogProgress(Controller, "IO thread stopping"); chip::DeviceLayer::StackUnlock unlock; chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); pthread_join(sIOThread, nullptr); sIOThread = PTHREAD_NULL; } return CHIP_NO_ERROR; } CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jbyteArray paseVerifier, jobject & outParams) { CHIP_ERROR err = CHIP_NO_ERROR; jmethodID constructor; jclass paramsClass; err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/PaseVerifierParams", paramsClass); SuccessOrExit(err); env->ExceptionClear(); constructor = env->GetMethodID(paramsClass, "", "(J[B)V"); VerifyOrExit(constructor != nullptr, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND); outParams = (jobject) env->NewObject(paramsClass, constructor, setupPincode, paseVerifier); VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); exit: return err; } CHIP_ERROR N2J_NetworkLocation(JNIEnv * env, jstring ipAddress, jint port, jint interfaceIndex, jobject & outLocation) { CHIP_ERROR err = CHIP_NO_ERROR; jmethodID constructor; jclass locationClass; err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/NetworkLocation", locationClass); SuccessOrExit(err); env->ExceptionClear(); constructor = env->GetMethodID(locationClass, "", "(Ljava/lang/String;II)V"); VerifyOrExit(constructor != nullptr, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND); outLocation = (jobject) env->NewObject(locationClass, constructor, ipAddress, port, interfaceIndex); VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); exit: return err; }