| /* |
| * 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 <lib/support/CHIPJNIError.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <vector> |
| |
| #include <string.h> |
| |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/JniReferences.h> |
| #include <lib/support/JniTypeWrappers.h> |
| |
| #include <controller/CHIPDeviceControllerFactory.h> |
| #include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h> |
| #include <credentials/attestation_verifier/DeviceAttestationVerifier.h> |
| #include <lib/core/TLV.h> |
| #include <lib/support/PersistentStorageMacros.h> |
| #include <lib/support/SafeInt.h> |
| #include <lib/support/ScopedBuffer.h> |
| #include <lib/support/TestGroupData.h> |
| #include <lib/support/ThreadOperationalDataset.h> |
| #include <platform/KeyValueStoreManager.h> |
| #ifndef JAVA_MATTER_CONTROLLER_TEST |
| #include <platform/android/CHIPP256KeypairBridge.h> |
| #endif // JAVA_MATTER_CONTROLLER_TEST |
| using namespace chip; |
| using namespace chip::Controller; |
| using namespace chip::Credentials; |
| using namespace TLV; |
| |
| AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper() |
| { |
| if ((mJavaVM != nullptr) && (mJavaObjectRef != nullptr)) |
| { |
| JniReferences::GetInstance().GetEnvForCurrentThread()->DeleteGlobalRef(mJavaObjectRef); |
| } |
| 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; |
| mJavaObjectRef = JniReferences::GetInstance().GetEnvForCurrentThread()->NewGlobalRef(obj); |
| } |
| |
| void AndroidDeviceControllerWrapper::CallJavaMethod(const char * methodName, jint argument) |
| { |
| JniReferences::GetInstance().CallVoidInt(JniReferences::GetInstance().GetEnvForCurrentThread(), mJavaObjectRef, 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<Inet::TCPEndPoint> * tcpEndPointManager, |
| chip::Inet::EndPointManager<Inet::UDPEndPoint> * 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, 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<DeviceCommissioner> controller(new DeviceCommissioner()); |
| |
| if (!controller) |
| { |
| *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; |
| return nullptr; |
| } |
| std::unique_ptr<AndroidDeviceControllerWrapper> 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 |
| const chip::Credentials::AttestationTrustStore * testingRootStore = chip::Credentials::GetTestAttestationTrustStore(); |
| chip::Credentials::SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); |
| |
| 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<chip::VendorId>(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->mAutoCommissioner.GetCommissioningParameters(); |
| params.SetFailsafeTimerSeconds(failsafeTimerSeconds); |
| params.SetAttemptWiFiNetworkScan(attemptNetworkScanWiFi); |
| params.SetAttemptThreadNetworkScan(attemptNetworkScanThread); |
| params.SetSkipCommissioningComplete(skipCommissioningComplete); |
| wrapper->UpdateCommissioningParameters(params); |
| |
| CHIP_ERROR err = wrapper->mGroupDataProvider.Init(); |
| if (err != CHIP_NO_ERROR) |
| { |
| *errInfoOnFailure = err; |
| return nullptr; |
| } |
| 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); |
| #endif |
| if (err != CHIP_NO_ERROR) |
| { |
| *errInfoOnFailure = err; |
| return nullptr; |
| } |
| |
| Platform::ScopedMemoryBuffer<uint8_t> noc; |
| if (!noc.Alloc(kMaxCHIPDERCertLength)) |
| { |
| *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; |
| return nullptr; |
| } |
| MutableByteSpan nocSpan(noc.Get(), kMaxCHIPDERCertLength); |
| |
| Platform::ScopedMemoryBuffer<uint8_t> icac; |
| if (!icac.Alloc(kMaxCHIPDERCertLength)) |
| { |
| *errInfoOnFailure = CHIP_ERROR_NO_MEMORY; |
| return nullptr; |
| } |
| |
| MutableByteSpan icacSpan(icac.Get(), kMaxCHIPDERCertLength); |
| |
| Platform::ScopedMemoryBuffer<uint8_t> 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<uint8_t>(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<uint8_t>(jniIcac.byteSpan().begin(), jniIcac.byteSpan().end()); |
| } |
| |
| wrapper->mNocCertificate = std::vector<uint8_t>(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; |
| } |
| |
| *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<unsigned>(wrapper->Controller()->GetFabricIndex())); |
| ChipLogByteSpan(Support, compressedFabricIdSpan); |
| |
| chip::ByteSpan ipkSpan; |
| std::vector<uint8_t> ipkBuffer; |
| if (ipkEpochKey != nullptr) |
| { |
| JniByteArray jniIpk(env, ipkEpochKey); |
| ipkBuffer = std::vector<uint8_t>(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); |
| |
| memset(ipkBuffer.data(), 0, ipkBuffer.size()); |
| |
| if (*errInfoOnFailure != CHIP_NO_ERROR) |
| { |
| return nullptr; |
| } |
| |
| return wrapper.release(); |
| } |
| |
| 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<jstring>(env->NewGlobalRef(env->CallObjectMethod(wifiCredentialsJava, getSsid))); |
| VerifyOrReturnError(ssidStr != nullptr && !env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| passwordStr = static_cast<jstring>(env->NewGlobalRef(env->CallObjectMethod(wifiCredentialsJava, getPassword))); |
| VerifyOrReturnError(ssidStr != nullptr && !env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| |
| ssid = env->GetStringUTFChars(ssidStr, 0); |
| password = env->GetStringUTFChars(passwordStr, 0); |
| jsize ssidLength = env->GetStringUTFLength(ssidStr); |
| jsize passwordLength = env->GetStringUTFLength(passwordStr); |
| |
| params.SetWiFiCredentials( |
| WiFiCredentials(chip::ByteSpan(reinterpret_cast<const uint8_t *>(ssid), static_cast<size_t>(ssidLength)), |
| chip::ByteSpan(reinterpret_cast<const uint8_t *>(password), static_cast<size_t>(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<jbyteArray>(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<const uint8_t *>(operationalDataset), static_cast<size_t>(length))); |
| } |
| else |
| { |
| ChipLogError(Controller, "Both WiFi and Thread credentials were null in NetworkCredentials"); |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| 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. |
| return mAutoCommissioner.SetCommissioningParameters(params); |
| } |
| |
| CHIP_ERROR AndroidDeviceControllerWrapper::UpdateDeviceAttestationDelegateBridge(jobject deviceAttestationDelegate, |
| chip::Optional<uint16_t> expiryTimeoutSecs, |
| bool shouldWaitAfterDeviceAttestation) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| DeviceAttestationDelegateBridge * delegateBridge = |
| new DeviceAttestationDelegateBridge(deviceAttestationDelegate, expiryTimeoutSecs, shouldWaitAfterDeviceAttestation); |
| VerifyOrExit(delegateBridge != nullptr, err = CHIP_ERROR_NO_MEMORY); |
| |
| if (mDeviceAttestationDelegateBridge != nullptr) |
| { |
| delete mDeviceAttestationDelegateBridge; |
| } |
| |
| mDeviceAttestationDelegateBridge = delegateBridge; |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR AndroidDeviceControllerWrapper::UpdateAttestationTrustStoreBridge(jobject attestationTrustStoreDelegate) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| DeviceAttestationVerifier * deviceAttestationVerifier = nullptr; |
| AttestationTrustStoreBridge * attestationTrustStoreBridge = new AttestationTrustStoreBridge(attestationTrustStoreDelegate); |
| 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; |
| |
| if (mDeviceAttestationVerifier != nullptr) |
| { |
| delete mDeviceAttestationVerifier; |
| } |
| mDeviceAttestationVerifier = deviceAttestationVerifier; |
| |
| mController->SetDeviceAttestationVerifier(mDeviceAttestationVerifier); |
| |
| exit: |
| if (err != CHIP_NO_ERROR) |
| { |
| if (attestationTrustStoreBridge != nullptr) |
| { |
| delete attestationTrustStoreBridge; |
| } |
| } |
| |
| return err; |
| } |
| |
| void AndroidDeviceControllerWrapper::OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) |
| { |
| chip::DeviceLayer::StackUnlock unlock; |
| CallJavaMethod("onStatusUpdate", static_cast<jint>(status)); |
| } |
| |
| void AndroidDeviceControllerWrapper::OnPairingComplete(CHIP_ERROR error) |
| { |
| chip::DeviceLayer::StackUnlock unlock; |
| CallJavaMethod("onPairingComplete", static_cast<jint>(error.AsInteger())); |
| } |
| |
| void AndroidDeviceControllerWrapper::OnPairingDeleted(CHIP_ERROR error) |
| { |
| chip::DeviceLayer::StackUnlock unlock; |
| CallJavaMethod("onPairingDeleted", static_cast<jint>(error.AsInteger())); |
| } |
| |
| void AndroidDeviceControllerWrapper::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) |
| { |
| chip::DeviceLayer::StackUnlock unlock; |
| JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); |
| jmethodID onCommissioningCompleteMethod; |
| CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef, "onCommissioningComplete", "(JI)V", |
| &onCommissioningCompleteMethod); |
| VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); |
| env->CallVoidMethod(mJavaObjectRef, onCommissioningCompleteMethod, static_cast<jlong>(deviceId), |
| static_cast<jint>(error.AsInteger())); |
| |
| if (ssidStr != nullptr) |
| { |
| env->ReleaseStringUTFChars(ssidStr, ssid); |
| env->DeleteGlobalRef(ssidStr); |
| } |
| if (passwordStr != nullptr) |
| { |
| env->ReleaseStringUTFChars(passwordStr, password); |
| env->DeleteGlobalRef(passwordStr); |
| } |
| 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(); |
| jmethodID onCommissioningStatusUpdateMethod; |
| CHIP_ERROR err = JniReferences::GetInstance().FindMethod(env, mJavaObjectRef, "onCommissioningStatusUpdate", |
| "(JLjava/lang/String;I)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, onCommissioningStatusUpdateMethod, static_cast<jlong>(peerId.GetNodeId()), |
| jStageCompleted.jniValue(), static_cast<jint>(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, "onReadCommissioningInfo", "(IIII)V", |
| &onReadCommissioningInfoMethod); |
| VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Error finding Java method: %" CHIP_ERROR_FORMAT, err.Format())); |
| |
| env->CallVoidMethod(mJavaObjectRef, onReadCommissioningInfoMethod, static_cast<jint>(info.basic.vendorId), |
| static_cast<jint>(info.basic.productId), static_cast<jint>(info.network.wifi.endpoint), |
| static_cast<jint>(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; |
| JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); |
| jmethodID javaMethod; |
| |
| VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Error invoking Java callback: no JNIEnv")); |
| |
| err = JniReferences::GetInstance().FindMethod( |
| env, mJavaObjectRef, "onScanNetworksSuccess", |
| "(Ljava/lang/Integer;Ljava/util/Optional;Ljava/util/Optional;Ljava/util/Optional;)V", &javaMethod); |
| VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Error invoking Java callback: %s", ErrorStr(err))); |
| |
| jobject NetworkingStatus; |
| std::string NetworkingStatusClassName = "java/lang/Integer"; |
| std::string NetworkingStatusCtorSignature = "(I)V"; |
| jint jniNetworkingStatus = static_cast<jint>(dataResponse.networkingStatus); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>( |
| NetworkingStatusClassName.c_str(), NetworkingStatusCtorSignature.c_str(), 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<jint>(entry.security.Raw()); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>(newElement_securityClassName.c_str(), |
| newElement_securityCtorSignature.c_str(), |
| jniNewElementSecurity, newElement_security); |
| jobject newElement_ssid; |
| jbyteArray newElement_ssidByteArray = env->NewByteArray(static_cast<jsize>(entry.ssid.size())); |
| env->SetByteArrayRegion(newElement_ssidByteArray, 0, static_cast<jsize>(entry.ssid.size()), |
| reinterpret_cast<const jbyte *>(entry.ssid.data())); |
| newElement_ssid = newElement_ssidByteArray; |
| jobject newElement_bssid; |
| jbyteArray newElement_bssidByteArray = env->NewByteArray(static_cast<jsize>(entry.bssid.size())); |
| env->SetByteArrayRegion(newElement_bssidByteArray, 0, static_cast<jsize>(entry.bssid.size()), |
| reinterpret_cast<const jbyte *>(entry.bssid.data())); |
| newElement_bssid = newElement_bssidByteArray; |
| jobject newElement_channel; |
| jint jniChannel = static_cast<jint>(entry.channel); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniChannel, newElement_channel); |
| jobject newElement_wiFiBand; |
| jint jniWiFiBand = static_cast<jint>(entry.wiFiBand); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniWiFiBand, |
| newElement_wiFiBand); |
| jobject newElement_rssi; |
| jint jniRssi = static_cast<jint>(entry.rssi); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniRssi, newElement_rssi); |
| |
| jclass wiFiInterfaceScanResultStructClass; |
| err = chip::JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/WiFiScanResult", |
| wiFiInterfaceScanResultStructClass); |
| if (err != CHIP_NO_ERROR) |
| { |
| ChipLogError(Zcl, "Could not find class WiFiScanResult"); |
| return; |
| } |
| jmethodID wiFiInterfaceScanResultStructCtor = |
| env->GetMethodID(wiFiInterfaceScanResultStructClass, "<init>", |
| "(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<jint>(entry.panId); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniPanId, newElement_panId); |
| jobject newElement_extendedPanId; |
| jlong jniExtendedPanId = static_cast<jlong>(entry.extendedPanId); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jlong>("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<jint>(entry.channel); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniChannel, newElement_channel); |
| jobject newElement_version; |
| jint jniVersion = static_cast<jint>(entry.version); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniVersion, newElement_version); |
| jobject newElement_extendedAddress; |
| jbyteArray newElement_extendedAddressByteArray = env->NewByteArray(static_cast<jsize>(entry.extendedAddress.size())); |
| env->SetByteArrayRegion(newElement_extendedAddressByteArray, 0, static_cast<jsize>(entry.extendedAddress.size()), |
| reinterpret_cast<const jbyte *>(entry.extendedAddress.data())); |
| newElement_extendedAddress = newElement_extendedAddressByteArray; |
| jobject newElement_rssi; |
| jint jniRssi = static_cast<jint>(entry.rssi); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniRssi, newElement_rssi); |
| jobject newElement_lqi; |
| jint jniLqi = static_cast<jint>(entry.lqi); |
| chip::JniReferences::GetInstance().CreateBoxedObject<jint>("java/lang/Integer", "(I)V", jniLqi, newElement_lqi); |
| |
| jclass threadInterfaceScanResultStructClass; |
| err = chip::JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/ThreadScanResult", |
| threadInterfaceScanResultStructClass); |
| if (err != CHIP_NO_ERROR) |
| { |
| ChipLogError(Zcl, "Could not find class ThreadScanResult"); |
| return; |
| } |
| jmethodID threadInterfaceScanResultStructCtor = |
| env->GetMethodID(threadInterfaceScanResultStructClass, "<init>", |
| "(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(Zcl, "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, javaMethod, NetworkingStatus, DebugText, WiFiScanResults, ThreadScanResults); |
| } |
| |
| void AndroidDeviceControllerWrapper::OnScanNetworksFailure(CHIP_ERROR error) |
| { |
| chip::DeviceLayer::StackUnlock unlock; |
| |
| CallJavaMethod("onScanNetworksFailure", static_cast<jint>(error.AsInteger())); |
| } |
| |
| CHIP_ERROR AndroidDeviceControllerWrapper::SyncGetKeyValue(const char * key, void * value, uint16_t & size) |
| { |
| ChipLogProgress(chipTool, "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<uint16_t>(read_size); |
| |
| return err; |
| } |
| |
| CHIP_ERROR AndroidDeviceControllerWrapper::SyncSetKeyValue(const char * key, const void * value, uint16_t size) |
| { |
| ChipLogProgress(chipTool, "KVS: Setting key %s", StringOrNullMarker(key)); |
| return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(key, value, size); |
| } |
| |
| CHIP_ERROR AndroidDeviceControllerWrapper::SyncDeleteKeyValue(const char * key) |
| { |
| ChipLogProgress(chipTool, "KVS: Deleting key %s", StringOrNullMarker(key)); |
| return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Delete(key); |
| } |