/* * 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. * */ #include "AndroidDeviceControllerWrapper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef JAVA_MATTER_CONTROLLER_TEST #include #endif // JAVA_MATTER_CONTROLLER_TEST using namespace chip; using namespace chip::Controller; using namespace chip::Credentials; using namespace TLV; AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper() { mController->Shutdown(); #ifndef JAVA_MATTER_CONTROLLER_TEST if (mKeypairBridge != nullptr) { chip::Platform::Delete(mKeypairBridge); mKeypairBridge = nullptr; } #endif // JAVA_MATTER_CONTROLLER_TEST if (mDeviceAttestationDelegateBridge != nullptr) { delete mDeviceAttestationDelegateBridge; mDeviceAttestationDelegateBridge = nullptr; } if (mDeviceAttestationVerifier != nullptr) { delete mDeviceAttestationVerifier; mDeviceAttestationVerifier = nullptr; } if (mAttestationTrustStoreBridge != nullptr) { delete mAttestationTrustStoreBridge; mAttestationTrustStoreBridge = nullptr; } } void AndroidDeviceControllerWrapper::SetJavaObjectRef(JavaVM * vm, jobject obj) { mJavaVM = vm; if (mJavaObjectRef.Init(obj) != CHIP_NO_ERROR) { ChipLogError(Controller, "Fail to init mJavaObjectRef"); } } void AndroidDeviceControllerWrapper::CallJavaIntMethod(const char * methodName, jint argument) { JniReferences::GetInstance().CallVoidInt(JniReferences::GetInstance().GetEnvForCurrentThread(), mJavaObjectRef.ObjectRef(), methodName, argument); } void AndroidDeviceControllerWrapper::CallJavaLongMethod(const char * methodName, jlong argument) { JniReferences::GetInstance().CallVoidLong(JniReferences::GetInstance().GetEnvForCurrentThread(), mJavaObjectRef.ObjectRef(), methodName, argument); } AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( JavaVM * vm, jobject deviceControllerObj, chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats, chip::System::Layer * systemLayer, chip::Inet::EndPointManager * tcpEndPointManager, chip::Inet::EndPointManager * udpEndPointManager, #ifdef JAVA_MATTER_CONTROLLER_TEST ExampleOperationalCredentialsIssuerPtr opCredsIssuerPtr, #else AndroidOperationalCredentialsIssuerPtr opCredsIssuerPtr, #endif jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, jbyteArray nodeOperationalCertificate, jbyteArray ipkEpochKey, uint16_t listenPort, uint16_t controllerVendorId, uint16_t failsafeTimerSeconds, bool attemptNetworkScanWiFi, bool attemptNetworkScanThread, bool skipCommissioningComplete, bool skipAttestationCertificateValidation, jstring countryCode, bool enableServerInteractions, CHIP_ERROR * errInfoOnFailure) { if (errInfoOnFailure == nullptr) { ChipLogError(Controller, "Missing error info"); return nullptr; } if (systemLayer == nullptr) { ChipLogError(Controller, "Missing system layer"); *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT; return nullptr; } if (tcpEndPointManager == nullptr) { ChipLogError(Controller, "Missing TCP layer"); *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT; return nullptr; } if (udpEndPointManager == nullptr) { ChipLogError(Controller, "Missing UDP layer"); *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT; return nullptr; } *errInfoOnFailure = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); if (env == nullptr) { ChipLogError(Controller, "Failed to retrieve JNIEnv."); *errInfoOnFailure = CHIP_ERROR_INCORRECT_STATE; return nullptr; } std::unique_ptr controller(new DeviceCommissioner()); if (!controller) { *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; return nullptr; } std::unique_ptr wrapper( new AndroidDeviceControllerWrapper(std::move(controller), std::move(opCredsIssuerPtr))); #ifdef JAVA_MATTER_CONTROLLER_TEST if (wrapper->mExampleStorage.Init() != CHIP_NO_ERROR) { ChipLogError(Controller, "Init Storage failure"); return nullptr; } chip::PersistentStorageDelegate * wrapperStorage = &wrapper->mExampleStorage; wrapper->SetJavaObjectRef(vm, deviceControllerObj); chip::Controller::ExampleOperationalCredentialsIssuer * opCredsIssuer = wrapper->mOpCredsIssuer.get(); #else chip::PersistentStorageDelegate * wrapperStorage = wrapper.get(); wrapper->SetJavaObjectRef(vm, deviceControllerObj); chip::Controller::AndroidOperationalCredentialsIssuer * opCredsIssuer = wrapper->mOpCredsIssuer.get(); #endif // Initialize device attestation verifier if (skipAttestationCertificateValidation) { chip::Credentials::SetDeviceAttestationVerifier(wrapper->GetPartialDACVerifier()); } else { const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore(); chip::Credentials::SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); } *errInfoOnFailure = getICDClientStorage()->Init(wrapperStorage, &wrapper->mSessionKeystore); if (*errInfoOnFailure != CHIP_NO_ERROR) { ChipLogError(Controller, "ICD Client Storage failure"); return nullptr; } chip::Controller::FactoryInitParams initParams; chip::Controller::SetupParams setupParams; initParams.systemLayer = systemLayer; initParams.tcpEndPointManager = tcpEndPointManager; initParams.udpEndPointManager = udpEndPointManager; // move bleLayer into platform/android to share with app server #if CONFIG_NETWORK_LAYER_BLE initParams.bleLayer = DeviceLayer::ConnectivityMgr().GetBleLayer(); #endif initParams.listenPort = listenPort; setupParams.controllerVendorId = static_cast(controllerVendorId); setupParams.pairingDelegate = wrapper.get(); setupParams.operationalCredentialsDelegate = opCredsIssuer; setupParams.defaultCommissioner = &wrapper->mAutoCommissioner; initParams.fabricIndependentStorage = wrapperStorage; initParams.sessionKeystore = &wrapper->mSessionKeystore; wrapper->mGroupDataProvider.SetStorageDelegate(wrapperStorage); wrapper->mGroupDataProvider.SetSessionKeystore(initParams.sessionKeystore); CommissioningParameters params = wrapper->GetCommissioningParameters(); params.SetFailsafeTimerSeconds(failsafeTimerSeconds); params.SetAttemptWiFiNetworkScan(attemptNetworkScanWiFi); params.SetAttemptThreadNetworkScan(attemptNetworkScanThread); params.SetSkipCommissioningComplete(skipCommissioningComplete); if (countryCode != nullptr) { JniUtfString countryCodeJniString(env, countryCode); if (countryCodeJniString.size() != kCountryCodeBufferLen) { *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT; return nullptr; } MutableCharSpan copiedCode(wrapper->mCountryCode); if (CopyCharSpanToMutableCharSpan(countryCodeJniString.charSpan(), copiedCode) != CHIP_NO_ERROR) { *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT; return nullptr; } params.SetCountryCode(copiedCode); } wrapper->UpdateCommissioningParameters(params); CHIP_ERROR err = wrapper->mGroupDataProvider.Init(); if (err != CHIP_NO_ERROR) { *errInfoOnFailure = err; return nullptr; } chip::Credentials::SetGroupDataProvider(&wrapper->mGroupDataProvider); initParams.groupDataProvider = &wrapper->mGroupDataProvider; err = wrapper->mOpCertStore.Init(wrapperStorage); if (err != CHIP_NO_ERROR) { *errInfoOnFailure = err; return nullptr; } initParams.opCertStore = &wrapper->mOpCertStore; #ifdef JAVA_MATTER_CONTROLLER_TEST err = opCredsIssuer->Initialize(wrapper->mExampleStorage); #else // TODO: Init IPK Epoch Key in opcreds issuer, so that commissionees get the right IPK err = opCredsIssuer->Initialize(*wrapper.get(), &wrapper->mAutoCommissioner, wrapper.get()->mJavaObjectRef.ObjectRef()); #endif if (err != CHIP_NO_ERROR) { *errInfoOnFailure = err; return nullptr; } Platform::ScopedMemoryBuffer noc; if (!noc.Alloc(kMaxCHIPDERCertLength)) { *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; return nullptr; } MutableByteSpan nocSpan(noc.Get(), kMaxCHIPDERCertLength); Platform::ScopedMemoryBuffer icac; if (!icac.Alloc(kMaxCHIPDERCertLength)) { *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; return nullptr; } MutableByteSpan icacSpan(icac.Get(), kMaxCHIPDERCertLength); Platform::ScopedMemoryBuffer rcac; if (!rcac.Alloc(kMaxCHIPDERCertLength)) { *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; return nullptr; } MutableByteSpan rcacSpan(rcac.Get(), kMaxCHIPDERCertLength); // The lifetime of the ephemeralKey variable must be kept until SetupParams is saved. Crypto::P256Keypair ephemeralKey; #ifndef JAVA_MATTER_CONTROLLER_TEST if (rootCertificate != nullptr && nodeOperationalCertificate != nullptr && keypairDelegate != nullptr) { CHIPP256KeypairBridge * nativeKeypairBridge = wrapper->GetP256KeypairBridge(); nativeKeypairBridge->SetDelegate(keypairDelegate); *errInfoOnFailure = nativeKeypairBridge->Initialize(Crypto::ECPKeyTarget::ECDSA); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; } setupParams.operationalKeypair = nativeKeypairBridge; setupParams.hasExternallyOwnedOperationalKeypair = true; JniByteArray jniRcac(env, rootCertificate); JniByteArray jniNoc(env, nodeOperationalCertificate); // Make copies of the cert that outlive the scope so that future factor init does not // cause loss of scope from the JNI refs going away. Also, this keeps the certs // handy for debugging commissioner init. wrapper->mRcacCertificate = std::vector(jniRcac.byteSpan().begin(), jniRcac.byteSpan().end()); // Intermediate cert could be missing. Let's only copy it if present wrapper->mIcacCertificate.clear(); if (intermediateCertificate != nullptr) { JniByteArray jniIcac(env, intermediateCertificate); wrapper->mIcacCertificate = std::vector(jniIcac.byteSpan().begin(), jniIcac.byteSpan().end()); } wrapper->mNocCertificate = std::vector(jniNoc.byteSpan().begin(), jniNoc.byteSpan().end()); setupParams.controllerRCAC = chip::ByteSpan(wrapper->mRcacCertificate.data(), wrapper->mRcacCertificate.size()); setupParams.controllerICAC = chip::ByteSpan(wrapper->mIcacCertificate.data(), wrapper->mIcacCertificate.size()); setupParams.controllerNOC = chip::ByteSpan(wrapper->mNocCertificate.data(), wrapper->mNocCertificate.size()); } else #endif // JAVA_MATTER_CONTROLLER_TEST { ChipLogProgress(Controller, "No existing credentials provided: generating ephemeral local NOC chain with OperationalCredentialsIssuer"); *errInfoOnFailure = ephemeralKey.Initialize(Crypto::ECPKeyTarget::ECDSA); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; } setupParams.operationalKeypair = &ephemeralKey; setupParams.hasExternallyOwnedOperationalKeypair = false; *errInfoOnFailure = opCredsIssuer->GenerateNOCChainAfterValidation(nodeId, fabricId, cats, ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; } setupParams.controllerRCAC = rcacSpan; setupParams.controllerICAC = icacSpan; setupParams.controllerNOC = nocSpan; } initParams.enableServerInteractions = enableServerInteractions; setupParams.enableServerInteractions = enableServerInteractions; *errInfoOnFailure = DeviceControllerFactory::GetInstance().Init(initParams); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; } *errInfoOnFailure = DeviceControllerFactory::GetInstance().SetupCommissioner(setupParams, *wrapper->Controller()); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; } // Setup IPK uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; chip::MutableByteSpan compressedFabricIdSpan(compressedFabricId); *errInfoOnFailure = wrapper->Controller()->GetCompressedFabricIdBytes(compressedFabricIdSpan); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; } ChipLogProgress(Controller, "Setting up group data for Fabric Index %u with Compressed Fabric ID:", static_cast(wrapper->Controller()->GetFabricIndex())); ChipLogByteSpan(Support, compressedFabricIdSpan); chip::ByteSpan ipkSpan; std::vector ipkBuffer; if (ipkEpochKey != nullptr) { JniByteArray jniIpk(env, ipkEpochKey); ipkBuffer = std::vector(jniIpk.byteSpan().begin(), jniIpk.byteSpan().end()); ipkSpan = chip::ByteSpan(ipkBuffer.data(), ipkBuffer.size()); } else { ipkSpan = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk(); } *errInfoOnFailure = chip::Credentials::SetSingleIpkEpochKey( &wrapper->mGroupDataProvider, wrapper->Controller()->GetFabricIndex(), ipkSpan, compressedFabricIdSpan); getICDClientStorage()->UpdateFabricList(wrapper->Controller()->GetFabricIndex()); auto engine = chip::app::InteractionModelEngine::GetInstance(); *errInfoOnFailure = wrapper->mCheckInDelegate.Init(getICDClientStorage(), engine); *errInfoOnFailure = wrapper->mCheckInHandler.Init(DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(), getICDClientStorage(), &wrapper->mCheckInDelegate, engine); memset(ipkBuffer.data(), 0, ipkBuffer.size()); if (*errInfoOnFailure != CHIP_NO_ERROR) { return nullptr; } return wrapper.release(); } void AndroidDeviceControllerWrapper::Shutdown() { mController->Shutdown(); DeviceControllerFactory::GetInstance().Shutdown(); } CHIP_ERROR AndroidDeviceControllerWrapper::ApplyNetworkCredentials(chip::Controller::CommissioningParameters & params, jobject networkCredentials) { chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; // Retrieve WiFi or Thread credentials from the NetworkCredentials Java object, and set them in the commissioning params. JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); jmethodID getWiFiCredentials; err = chip::JniReferences::GetInstance().FindMethod(env, networkCredentials, "getWiFiCredentials", "()Lchip/devicecontroller/NetworkCredentials$WiFiCredentials;", &getWiFiCredentials); VerifyOrReturnError(err == CHIP_NO_ERROR, err); jobject wifiCredentialsJava = env->CallObjectMethod(networkCredentials, getWiFiCredentials); jmethodID getThreadCredentials; err = chip::JniReferences::GetInstance().FindMethod(env, networkCredentials, "getThreadCredentials", "()Lchip/devicecontroller/NetworkCredentials$ThreadCredentials;", &getThreadCredentials); VerifyOrReturnError(err == CHIP_NO_ERROR, err); jobject threadCredentialsJava = env->CallObjectMethod(networkCredentials, getThreadCredentials); if (wifiCredentialsJava != nullptr) { jmethodID getSsid; jmethodID getPassword; err = chip::JniReferences::GetInstance().FindMethod(env, wifiCredentialsJava, "getSsid", "()Ljava/lang/String;", &getSsid); VerifyOrReturnError(err == CHIP_NO_ERROR, err); err = chip::JniReferences::GetInstance().FindMethod(env, wifiCredentialsJava, "getPassword", "()Ljava/lang/String;", &getPassword); VerifyOrReturnError(err == CHIP_NO_ERROR, err); ssidStr = static_cast(env->NewGlobalRef(env->CallObjectMethod(wifiCredentialsJava, getSsid))); VerifyOrReturnError(ssidStr != nullptr && !env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); passwordStr = static_cast(env->NewGlobalRef(env->CallObjectMethod(wifiCredentialsJava, getPassword))); VerifyOrReturnError(ssidStr != nullptr && !env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); ssid = env->GetStringUTFChars(ssidStr, nullptr); password = env->GetStringUTFChars(passwordStr, nullptr); jsize ssidLength = env->GetStringUTFLength(ssidStr); jsize passwordLength = env->GetStringUTFLength(passwordStr); params.SetWiFiCredentials( WiFiCredentials(chip::ByteSpan(reinterpret_cast(ssid), static_cast(ssidLength)), chip::ByteSpan(reinterpret_cast(password), static_cast(passwordLength)))); } else if (threadCredentialsJava != nullptr) { jmethodID getOperationalDataset; err = chip::JniReferences::GetInstance().FindMethod(env, threadCredentialsJava, "getOperationalDataset", "()[B", &getOperationalDataset); VerifyOrReturnError(err == CHIP_NO_ERROR, err); operationalDatasetBytes = static_cast(env->NewGlobalRef(env->CallObjectMethod(threadCredentialsJava, getOperationalDataset))); VerifyOrReturnError(operationalDatasetBytes != nullptr && !env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); operationalDataset = env->GetByteArrayElements(operationalDatasetBytes, nullptr); jsize length = env->GetArrayLength(operationalDatasetBytes); params.SetThreadOperationalDataset( chip::ByteSpan(reinterpret_cast(operationalDataset), static_cast(length))); } else { ChipLogError(Controller, "Both WiFi and Thread credentials were null in NetworkCredentials"); return CHIP_ERROR_INCORRECT_STATE; } return err; } CHIP_ERROR AndroidDeviceControllerWrapper::ApplyICDRegistrationInfo(chip::Controller::CommissioningParameters & params, jobject icdRegistrationInfo) { chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; mDeviceIsICD = false; VerifyOrReturnError(icdRegistrationInfo != nullptr, CHIP_ERROR_INVALID_ARGUMENT); JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); if (env == nullptr) { ChipLogError(Controller, "Failed to retrieve JNIEnv in %s.", __func__); return CHIP_ERROR_INCORRECT_STATE; } jmethodID getICDStayActiveDurationMsecMethod; err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getICDStayActiveDurationMsec", "()Ljava/lang/Long;", &getICDStayActiveDurationMsecMethod); ReturnErrorOnFailure(err); jobject jStayActiveMsec = env->CallObjectMethod(icdRegistrationInfo, getICDStayActiveDurationMsecMethod); if (jStayActiveMsec != nullptr) { jlong stayActiveMsec = chip::JniReferences::GetInstance().LongToPrimitive(jStayActiveMsec); if (!chip::CanCastTo(stayActiveMsec)) { ChipLogError(Controller, "Failed to process stayActiveMsec in %s since this is not a valid 32-bit integer.", __func__); return CHIP_ERROR_INVALID_ARGUMENT; } params.SetICDStayActiveDurationMsec(static_cast(stayActiveMsec)); } jmethodID getCheckInNodeIdMethod; err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getCheckInNodeId", "()Ljava/lang/Long;", &getCheckInNodeIdMethod); ReturnErrorOnFailure(err); jobject jCheckInNodeId = env->CallObjectMethod(icdRegistrationInfo, getCheckInNodeIdMethod); jmethodID getMonitoredSubjectMethod; err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getMonitoredSubject", "()Ljava/lang/Long;", &getMonitoredSubjectMethod); ReturnErrorOnFailure(err); jobject jMonitoredSubject = env->CallObjectMethod(icdRegistrationInfo, getMonitoredSubjectMethod); jmethodID getSymmetricKeyMethod; err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getSymmetricKey", "()[B", &getSymmetricKeyMethod); ReturnErrorOnFailure(err); jbyteArray jSymmetricKey = static_cast(env->CallObjectMethod(icdRegistrationInfo, getSymmetricKeyMethod)); jmethodID getClientTypeMethod; err = chip::JniReferences::GetInstance().FindMethod(env, icdRegistrationInfo, "getClientType", "()Ljava/lang/Integer;", &getClientTypeMethod); ReturnErrorOnFailure(err); jobject jClientType = env->CallObjectMethod(icdRegistrationInfo, getClientTypeMethod); chip::NodeId checkInNodeId = chip::kUndefinedNodeId; if (jCheckInNodeId != nullptr) { checkInNodeId = static_cast(chip::JniReferences::GetInstance().LongToPrimitive(jCheckInNodeId)); } else { checkInNodeId = mController->GetNodeId(); } params.SetICDCheckInNodeId(checkInNodeId); uint64_t monitoredSubject = static_cast(checkInNodeId); if (jMonitoredSubject != nullptr) { monitoredSubject = static_cast(chip::JniReferences::GetInstance().LongToPrimitive(jMonitoredSubject)); } params.SetICDMonitoredSubject(monitoredSubject); if (jSymmetricKey != nullptr) { JniByteArray jniSymmetricKey(env, jSymmetricKey); VerifyOrReturnError(jniSymmetricKey.size() == sizeof(mICDSymmetricKey), CHIP_ERROR_INVALID_ARGUMENT); memcpy(mICDSymmetricKey, jniSymmetricKey.data(), sizeof(mICDSymmetricKey)); } else { chip::Crypto::DRBG_get_bytes(mICDSymmetricKey, sizeof(mICDSymmetricKey)); } params.SetICDSymmetricKey(chip::ByteSpan(mICDSymmetricKey)); chip::app::Clusters::IcdManagement::ClientTypeEnum clientType = chip::app::Clusters::IcdManagement::ClientTypeEnum::kPermanent; if (jClientType != nullptr) { clientType = static_cast( chip::JniReferences::GetInstance().IntegerToPrimitive(jClientType)); } params.SetICDClientType(clientType); return err; } CHIP_ERROR AndroidDeviceControllerWrapper::UpdateCommissioningParameters(const chip::Controller::CommissioningParameters & params) { // this will wipe out any custom attestationNonce and csrNonce that was being used. // however, Android APIs don't allow these to be set to custom values today. mCommissioningParameter = params; return mAutoCommissioner.SetCommissioningParameters(params); } CHIP_ERROR AndroidDeviceControllerWrapper::UpdateDeviceAttestationDelegateBridge(jobject deviceAttestationDelegate, chip::Optional expiryTimeoutSecs, bool shouldWaitAfterDeviceAttestation) { chip::JniGlobalReference deviceAttestationDelegateRef; ReturnErrorOnFailure(deviceAttestationDelegateRef.Init(deviceAttestationDelegate)); DeviceAttestationDelegateBridge * delegateBridge = new DeviceAttestationDelegateBridge( std::move(deviceAttestationDelegateRef), expiryTimeoutSecs, shouldWaitAfterDeviceAttestation); VerifyOrReturnError(delegateBridge != nullptr, CHIP_ERROR_NO_MEMORY); if (mDeviceAttestationDelegateBridge != nullptr) { delete mDeviceAttestationDelegateBridge; } mDeviceAttestationDelegateBridge = delegateBridge; return CHIP_NO_ERROR; } CHIP_ERROR AndroidDeviceControllerWrapper::UpdateAttestationTrustStoreBridge(jobject attestationTrustStoreDelegate, jobject cdTrustKeys) { CHIP_ERROR err = CHIP_NO_ERROR; DeviceAttestationVerifier * deviceAttestationVerifier = nullptr; chip::JniGlobalReference attestationTrustStoreDelegateRef; ReturnErrorOnFailure(attestationTrustStoreDelegateRef.Init(attestationTrustStoreDelegate)); AttestationTrustStoreBridge * attestationTrustStoreBridge = new AttestationTrustStoreBridge(std::move(attestationTrustStoreDelegateRef)); VerifyOrExit(attestationTrustStoreBridge != nullptr, err = CHIP_ERROR_NO_MEMORY); deviceAttestationVerifier = new Credentials::DefaultDACVerifier(attestationTrustStoreBridge); VerifyOrExit(deviceAttestationVerifier != nullptr, err = CHIP_ERROR_NO_MEMORY); if (mAttestationTrustStoreBridge != nullptr) { delete mAttestationTrustStoreBridge; } mAttestationTrustStoreBridge = attestationTrustStoreBridge; attestationTrustStoreBridge = nullptr; if (mDeviceAttestationVerifier != nullptr) { delete mDeviceAttestationVerifier; } mDeviceAttestationVerifier = deviceAttestationVerifier; deviceAttestationVerifier = nullptr; if (cdTrustKeys != nullptr) { WellKnownKeysTrustStore * cdTrustStore = mDeviceAttestationVerifier->GetCertificationDeclarationTrustStore(); VerifyOrExit(cdTrustStore != nullptr, err = CHIP_ERROR_INCORRECT_STATE); jint size; err = JniReferences::GetInstance().GetListSize(cdTrustKeys, size); VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_ERROR_INVALID_ARGUMENT); for (jint i = 0; i < size; i++) { jobject jTrustKey = nullptr; err = JniReferences::GetInstance().GetListItem(cdTrustKeys, i, jTrustKey); VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_ERROR_INVALID_ARGUMENT); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); JniByteArray jniTrustKey(env, static_cast(jTrustKey)); err = cdTrustStore->AddTrustedKey(jniTrustKey.byteSpan()); VerifyOrExit(err == CHIP_NO_ERROR, err = CHIP_ERROR_INVALID_ARGUMENT); } } mController->SetDeviceAttestationVerifier(mDeviceAttestationVerifier); exit: if (err != CHIP_NO_ERROR) { if (attestationTrustStoreBridge != nullptr) { delete attestationTrustStoreBridge; attestationTrustStoreBridge = nullptr; } } return err; } CHIP_ERROR AndroidDeviceControllerWrapper::StartOTAProvider(jobject otaProviderDelegate) { #if CHIP_DEVICE_CONFIG_DYNAMIC_SERVER CHIP_ERROR err = CHIP_NO_ERROR; OTAProviderDelegateBridge * otaProviderBridge = new OTAProviderDelegateBridge(); auto systemState = DeviceControllerFactory::GetInstance().GetSystemState(); VerifyOrExit(otaProviderBridge != nullptr, err = CHIP_ERROR_NO_MEMORY); err = otaProviderBridge->Init(systemState->SystemLayer(), systemState->ExchangeMgr(), otaProviderDelegate); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "OTA Provider Initialize Error : %" CHIP_ERROR_FORMAT, err.Format())); mOtaProviderBridge = otaProviderBridge; exit: if (err != CHIP_NO_ERROR) { if (otaProviderBridge != nullptr) { delete otaProviderBridge; otaProviderBridge = nullptr; } } return err; #else return CHIP_ERROR_NOT_IMPLEMENTED; #endif } CHIP_ERROR AndroidDeviceControllerWrapper::FinishOTAProvider() { #if CHIP_DEVICE_CONFIG_DYNAMIC_SERVER if (mOtaProviderBridge != nullptr) { mOtaProviderBridge->Shutdown(); delete mOtaProviderBridge; mOtaProviderBridge = nullptr; } return CHIP_NO_ERROR; #else return CHIP_ERROR_NOT_IMPLEMENTED; #endif } CHIP_ERROR AndroidDeviceControllerWrapper::SetICDCheckInDelegate(jobject checkInDelegate) { return mCheckInDelegate.SetDelegate(checkInDelegate); } void AndroidDeviceControllerWrapper::OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) { chip::DeviceLayer::StackUnlock unlock; CallJavaIntMethod("onStatusUpdate", static_cast(status)); } void AndroidDeviceControllerWrapper::OnPairingComplete(CHIP_ERROR error) { chip::DeviceLayer::StackUnlock unlock; CallJavaLongMethod("onPairingComplete", static_cast(error.AsInteger())); } void AndroidDeviceControllerWrapper::OnPairingDeleted(CHIP_ERROR error) { chip::DeviceLayer::StackUnlock unlock; CallJavaLongMethod("onPairingDeleted", static_cast(error.AsInteger())); } void AndroidDeviceControllerWrapper::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) { chip::DeviceLayer::StackUnlock unlock; if (error != CHIP_NO_ERROR && mDeviceIsICD) { CHIP_ERROR deleteEntryError = getICDClientStorage()->DeleteEntry(ScopedNodeId(deviceId, Controller()->GetFabricIndex())); if (deleteEntryError != CHIP_NO_ERROR) { ChipLogError(chipTool, "Failed to delete ICD entry: %" CHIP_ERROR_FORMAT, deleteEntryError.Format()); } } JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); jmethodID onCommissioningCompleteMethod; CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef.ObjectRef(), "onCommissioningComplete", "(JJ)V", &onCommissioningCompleteMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); env->CallVoidMethod(mJavaObjectRef.ObjectRef(), onCommissioningCompleteMethod, static_cast(deviceId), static_cast(error.AsInteger())); if (ssidStr != nullptr) { env->ReleaseStringUTFChars(ssidStr, ssid); env->DeleteGlobalRef(ssidStr); ssidStr = nullptr; } if (passwordStr != nullptr) { env->ReleaseStringUTFChars(passwordStr, password); env->DeleteGlobalRef(passwordStr); passwordStr = nullptr; } if (operationalDatasetBytes != nullptr) { env->ReleaseByteArrayElements(operationalDatasetBytes, operationalDataset, 0); env->DeleteGlobalRef(operationalDatasetBytes); operationalDatasetBytes = nullptr; } } void AndroidDeviceControllerWrapper::OnCommissioningStatusUpdate(PeerId peerId, chip::Controller::CommissioningStage stageCompleted, CHIP_ERROR error) { chip::DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); jmethodID onCommissioningStatusUpdateMethod; CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef.ObjectRef(), "onCommissioningStatusUpdate", "(JLjava/lang/String;J)V", &onCommissioningStatusUpdateMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); UtfString jStageCompleted(env, StageToString(stageCompleted)); env->CallVoidMethod(mJavaObjectRef.ObjectRef(), onCommissioningStatusUpdateMethod, static_cast(peerId.GetNodeId()), jStageCompleted.jniValue(), static_cast(error.AsInteger())); } void AndroidDeviceControllerWrapper::OnReadCommissioningInfo(const chip::Controller::ReadCommissioningInfo & info) { // calls: onReadCommissioningInfo(int vendorId, int productId, int wifiEndpointId, int threadEndpointId) chip::DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); jmethodID onReadCommissioningInfoMethod; CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef.ObjectRef(), "onReadCommissioningInfo", "(IIII)V", &onReadCommissioningInfoMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); // For ICD mUserActiveModeTriggerHint = info.icd.userActiveModeTriggerHint; memset(mUserActiveModeTriggerInstructionBuffer, 0x00, kUserActiveModeTriggerInstructionBufferLen); CopyCharSpanToMutableCharSpan(info.icd.userActiveModeTriggerInstruction, mUserActiveModeTriggerInstruction); ChipLogProgress(AppServer, "OnReadCommissioningInfo ICD - IdleModeDuration=%u activeModeDuration=%u activeModeThreshold=%u", info.icd.idleModeDuration, info.icd.activeModeDuration, info.icd.activeModeThreshold); env->CallVoidMethod(mJavaObjectRef.ObjectRef(), onReadCommissioningInfoMethod, static_cast(info.basic.vendorId), static_cast(info.basic.productId), static_cast(info.network.wifi.endpoint), static_cast(info.network.thread.endpoint)); } void AndroidDeviceControllerWrapper::OnScanNetworksSuccess( const chip::app::Clusters::NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & dataResponse) { chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; jmethodID javaMethod; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Error invoking Java callback: no JNIEnv")); err = JniReferences::GetInstance().FindMethod( env, mJavaObjectRef.ObjectRef(), "onScanNetworksSuccess", "(Ljava/lang/Integer;Ljava/util/Optional;Ljava/util/Optional;Ljava/util/Optional;)V", &javaMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error invoking Java callback: %s", ErrorStr(err))); jobject NetworkingStatus; std::string NetworkingStatusClassName = "java/lang/Integer"; std::string NetworkingStatusCtorSignature = "(I)V"; jint jniNetworkingStatus = static_cast(dataResponse.networkingStatus); chip::JniReferences::GetInstance().CreateBoxedObject(NetworkingStatusClassName, NetworkingStatusCtorSignature, jniNetworkingStatus, NetworkingStatus); jobject DebugText; if (!dataResponse.debugText.HasValue()) { chip::JniReferences::GetInstance().CreateOptional(nullptr, DebugText); } else { jobject DebugTextInsideOptional; DebugTextInsideOptional = env->NewStringUTF(std::string(dataResponse.debugText.Value().data(), dataResponse.debugText.Value().size()).c_str()); chip::JniReferences::GetInstance().CreateOptional(DebugTextInsideOptional, DebugText); } jobject WiFiScanResults; if (!dataResponse.wiFiScanResults.HasValue()) { chip::JniReferences::GetInstance().CreateOptional(nullptr, WiFiScanResults); } else { // TODO: use this jobject WiFiScanResultsInsideOptional; chip::JniReferences::GetInstance().CreateArrayList(WiFiScanResultsInsideOptional); auto iter_WiFiScanResultsInsideOptional = dataResponse.wiFiScanResults.Value().begin(); while (iter_WiFiScanResultsInsideOptional.Next()) { auto & entry = iter_WiFiScanResultsInsideOptional.GetValue(); jobject newElement_security; std::string newElement_securityClassName = "java/lang/Integer"; std::string newElement_securityCtorSignature = "(I)V"; jint jniNewElementSecurity = static_cast(entry.security.Raw()); chip::JniReferences::GetInstance().CreateBoxedObject( newElement_securityClassName, newElement_securityCtorSignature, jniNewElementSecurity, newElement_security); jobject newElement_ssid; jbyteArray newElement_ssidByteArray = env->NewByteArray(static_cast(entry.ssid.size())); env->SetByteArrayRegion(newElement_ssidByteArray, 0, static_cast(entry.ssid.size()), reinterpret_cast(entry.ssid.data())); newElement_ssid = newElement_ssidByteArray; jobject newElement_bssid; jbyteArray newElement_bssidByteArray = env->NewByteArray(static_cast(entry.bssid.size())); env->SetByteArrayRegion(newElement_bssidByteArray, 0, static_cast(entry.bssid.size()), reinterpret_cast(entry.bssid.data())); newElement_bssid = newElement_bssidByteArray; jobject newElement_channel; jint jniChannel = static_cast(entry.channel); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniChannel, newElement_channel); jobject newElement_wiFiBand; jint jniWiFiBand = static_cast(entry.wiFiBand); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniWiFiBand, newElement_wiFiBand); jobject newElement_rssi; jint jniRssi = static_cast(entry.rssi); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniRssi, newElement_rssi); jclass wiFiInterfaceScanResultStructClass; err = chip::JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/WiFiScanResult", wiFiInterfaceScanResultStructClass); if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "Could not find class WiFiScanResult"); return; } jmethodID wiFiInterfaceScanResultStructCtor = env->GetMethodID(wiFiInterfaceScanResultStructClass, "", "(Ljava/lang/Integer;[B[BLjava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)V"); if (wiFiInterfaceScanResultStructCtor == nullptr) { ChipLogError(Zcl, "Could not find WiFiScanResult constructor"); return; } jobject newElement = env->NewObject(wiFiInterfaceScanResultStructClass, wiFiInterfaceScanResultStructCtor, newElement_security, newElement_ssid, newElement_bssid, newElement_channel, newElement_wiFiBand, newElement_rssi); chip::JniReferences::GetInstance().AddToList(WiFiScanResultsInsideOptional, newElement); } chip::JniReferences::GetInstance().CreateOptional(WiFiScanResultsInsideOptional, WiFiScanResults); } jobject ThreadScanResults; if (!dataResponse.threadScanResults.HasValue()) { chip::JniReferences::GetInstance().CreateOptional(nullptr, ThreadScanResults); } else { jobject ThreadScanResultsInsideOptional; chip::JniReferences::GetInstance().CreateArrayList(ThreadScanResultsInsideOptional); auto iter_ThreadScanResultsInsideOptional = dataResponse.threadScanResults.Value().begin(); while (iter_ThreadScanResultsInsideOptional.Next()) { auto & entry = iter_ThreadScanResultsInsideOptional.GetValue(); jobject newElement_panId; jint jniPanId = static_cast(entry.panId); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniPanId, newElement_panId); jobject newElement_extendedPanId; jlong jniExtendedPanId = static_cast(entry.extendedPanId); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Long", "(J)V", jniExtendedPanId, newElement_extendedPanId); jobject newElement_networkName; newElement_networkName = env->NewStringUTF(std::string(entry.networkName.data(), entry.networkName.size()).c_str()); jobject newElement_channel; jint jniChannel = static_cast(entry.channel); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniChannel, newElement_channel); jobject newElement_version; jint jniVersion = static_cast(entry.version); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniVersion, newElement_version); jobject newElement_extendedAddress; jbyteArray newElement_extendedAddressByteArray = env->NewByteArray(static_cast(entry.extendedAddress.size())); env->SetByteArrayRegion(newElement_extendedAddressByteArray, 0, static_cast(entry.extendedAddress.size()), reinterpret_cast(entry.extendedAddress.data())); newElement_extendedAddress = newElement_extendedAddressByteArray; jobject newElement_rssi; jint jniRssi = static_cast(entry.rssi); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniRssi, newElement_rssi); jobject newElement_lqi; jint jniLqi = static_cast(entry.lqi); chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", jniLqi, newElement_lqi); jclass threadInterfaceScanResultStructClass; err = chip::JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/ThreadScanResult", threadInterfaceScanResultStructClass); if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Could not find class ThreadScanResult"); return; } jmethodID threadInterfaceScanResultStructCtor = env->GetMethodID(threadInterfaceScanResultStructClass, "", "(Ljava/lang/Integer;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/" "Integer;[BLjava/lang/Integer;Ljava/lang/Integer;)V"); if (threadInterfaceScanResultStructCtor == nullptr) { ChipLogError(Controller, "Could not find ThreadScanResult constructor"); return; } jobject newElement = env->NewObject(threadInterfaceScanResultStructClass, threadInterfaceScanResultStructCtor, newElement_panId, newElement_extendedPanId, newElement_networkName, newElement_channel, newElement_version, newElement_extendedAddress, newElement_rssi, newElement_lqi); chip::JniReferences::GetInstance().AddToList(ThreadScanResultsInsideOptional, newElement); } chip::JniReferences::GetInstance().CreateOptional(ThreadScanResultsInsideOptional, ThreadScanResults); } env->CallVoidMethod(mJavaObjectRef.ObjectRef(), javaMethod, NetworkingStatus, DebugText, WiFiScanResults, ThreadScanResults); } void AndroidDeviceControllerWrapper::OnScanNetworksFailure(CHIP_ERROR error) { chip::DeviceLayer::StackUnlock unlock; CallJavaLongMethod("onScanNetworksFailure", static_cast(error.AsInteger())); } void AndroidDeviceControllerWrapper::OnICDRegistrationInfoRequired() { chip::DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); jmethodID onICDRegistrationInfoRequiredMethod; CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef.ObjectRef(), "onICDRegistrationInfoRequired", "()V", &onICDRegistrationInfoRequiredMethod); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); env->CallVoidMethod(mJavaObjectRef.ObjectRef(), onICDRegistrationInfoRequiredMethod); } void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::ScopedNodeId icdNodeId, uint32_t icdCounter) { chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; chip::app::ICDClientInfo clientInfo; clientInfo.peer_node = icdNodeId; clientInfo.check_in_node = chip::ScopedNodeId(mAutoCommissioner.GetCommissioningParameters().GetICDCheckInNodeId().Value(), icdNodeId.GetFabricIndex()); clientInfo.monitored_subject = mAutoCommissioner.GetCommissioningParameters().GetICDMonitoredSubject().Value(); clientInfo.start_icd_counter = icdCounter; ByteSpan symmetricKey = mAutoCommissioner.GetCommissioningParameters().GetICDSymmetricKey().Value(); err = getICDClientStorage()->SetKey(clientInfo, symmetricKey); if (err == CHIP_NO_ERROR) { err = getICDClientStorage()->StoreEntry(clientInfo); } if (err == CHIP_NO_ERROR) { ChipLogProgress(Controller, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(icdNodeId.GetNodeId())); } else { getICDClientStorage()->RemoveKey(clientInfo); ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(icdNodeId.GetNodeId()), err.AsString()); } mDeviceIsICD = true; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); JniLocalReferenceScope scope(env); jmethodID onICDRegistrationCompleteMethod; jclass icdDeviceInfoClass = nullptr; jmethodID icdDeviceInfoStructCtor = nullptr; jobject icdDeviceInfoObj = nullptr; jbyteArray jSymmetricKey = nullptr; CHIP_ERROR methodErr = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef.ObjectRef(), "onICDRegistrationComplete", "(JLchip/devicecontroller/ICDDeviceInfo;)V", &onICDRegistrationCompleteMethod); VerifyOrReturn(methodErr == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, methodErr.Format())); methodErr = chip::JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/ICDDeviceInfo", icdDeviceInfoClass); VerifyOrReturn(methodErr == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find class ICDDeviceInfo")); icdDeviceInfoStructCtor = env->GetMethodID(icdDeviceInfoClass, "", "([BILjava/lang/String;JJIJJJJJI)V"); VerifyOrReturn(icdDeviceInfoStructCtor != nullptr, ChipLogError(Controller, "Could not find ICDDeviceInfo constructor")); methodErr = JniReferences::GetInstance().N2J_ByteArray(env, symmetricKey.data(), static_cast(symmetricKey.size()), jSymmetricKey); VerifyOrReturn(methodErr == CHIP_NO_ERROR, ChipLogError(Controller, "Error Parsing Symmetric Key: %" CHIP_ERROR_FORMAT, methodErr.Format())); jstring jUserActiveModeTriggerInstruction = env->NewStringUTF(mUserActiveModeTriggerInstruction.data()); icdDeviceInfoObj = env->NewObject( icdDeviceInfoClass, icdDeviceInfoStructCtor, jSymmetricKey, static_cast(mUserActiveModeTriggerHint.Raw()), jUserActiveModeTriggerInstruction, static_cast(mIdleModeDuration), static_cast(mActiveModeDuration), static_cast(mActiveModeThreshold), static_cast(icdNodeId.GetNodeId()), static_cast(mAutoCommissioner.GetCommissioningParameters().GetICDCheckInNodeId().Value()), static_cast(icdCounter), static_cast(mAutoCommissioner.GetCommissioningParameters().GetICDMonitoredSubject().Value()), static_cast(Controller()->GetFabricId()), static_cast(Controller()->GetFabricIndex())); env->CallVoidMethod(mJavaObjectRef.ObjectRef(), onICDRegistrationCompleteMethod, static_cast(err.AsInteger()), icdDeviceInfoObj); } CHIP_ERROR AndroidDeviceControllerWrapper::SyncGetKeyValue(const char * key, void * value, uint16_t & size) { ChipLogProgress(Controller, "KVS: Getting key %s", StringOrNullMarker(key)); size_t read_size = 0; CHIP_ERROR err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Get(key, value, size, &read_size); size = static_cast(read_size); return err; } CHIP_ERROR AndroidDeviceControllerWrapper::SyncSetKeyValue(const char * key, const void * value, uint16_t size) { ChipLogProgress(Controller, "KVS: Setting key %s", StringOrNullMarker(key)); return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(key, value, size); } CHIP_ERROR AndroidDeviceControllerWrapper::SyncDeleteKeyValue(const char * key) { ChipLogProgress(Controller, "KVS: Deleting key %s", StringOrNullMarker(key)); return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Delete(key); } void AndroidDeviceControllerWrapper::StartDnssd() { FabricTable * fabricTable = DeviceControllerFactory::GetInstance().GetSystemState()->Fabrics(); VerifyOrReturn(fabricTable != nullptr, ChipLogError(Controller, "Fail to get fabricTable in StartDnssd")); chip::app::DnssdServer::Instance().SetFabricTable(fabricTable); chip::app::DnssdServer::Instance().StartServer(); } void AndroidDeviceControllerWrapper::StopDnssd() { chip::app::DnssdServer::Instance().StopServer(); }