/* * * Copyright (c) 2021 Project CHIP Authors * * 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 * Provides an implementation of the DiagnosticDataProvider object * for android platform. */ #include #include #include #include #include "DiagnosticDataProviderImpl.h" #include #include #include #include #include #include #include using namespace ::chip::app::Clusters::GeneralDiagnostics; namespace chip { namespace DeviceLayer { DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance() { static DiagnosticDataProviderImpl sInstance; return sInstance; } void DiagnosticDataProviderImpl::InitializeWithObject(jobject manager) { JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(DeviceLayer, "Failed to GetEnvForCurrentThread for DiagnosticDataProviderManagerImpl")); VerifyOrReturn(mDiagnosticDataProviderManagerObject.Init(manager) == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to Init DiagnosticDataProviderManager")); jclass DiagnosticDataProviderManagerClass = env->GetObjectClass(manager); VerifyOrReturn(DiagnosticDataProviderManagerClass != nullptr, ChipLogError(DeviceLayer, "Failed to get DiagnosticDataProviderManager Java class")); mGetRebootCountMethod = env->GetMethodID(DiagnosticDataProviderManagerClass, "getRebootCount", "()I"); if (mGetRebootCountMethod == nullptr) { ChipLogError(DeviceLayer, "Failed to access DiagnosticDataProviderManager 'getRebootCount' method"); env->ExceptionClear(); } mGetNifMethod = env->GetMethodID(DiagnosticDataProviderManagerClass, "getNetworkInterfaces", "()[Lchip/platform/NetworkInterface;"); if (mGetNifMethod == nullptr) { ChipLogError(DeviceLayer, "Failed to access DiagnosticDataProviderManager 'getNetworkInterfaces' method"); env->ExceptionClear(); } } CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount) { chip::DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnLogError(mDiagnosticDataProviderManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnLogError(mGetRebootCountMethod != nullptr, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); ChipLogProgress(DeviceLayer, "Received GetRebootCount"); jint count = env->CallIntMethod(mDiagnosticDataProviderManagerObject.ObjectRef(), mGetRebootCountMethod); VerifyOrReturnLogError(count < UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); rebootCount = static_cast(count); return CHIP_NO_ERROR; } CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** netifpp) { chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(DeviceLayer, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); VerifyOrExit(mDiagnosticDataProviderManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetNifMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); { ChipLogProgress(DeviceLayer, "Received GetNetworkInterfaces"); jobjectArray nifList = (jobjectArray) env->CallObjectMethod(mDiagnosticDataProviderManagerObject.ObjectRef(), mGetNifMethod); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in DiagnosticDataProviderImpl::GetNetworkInterfaces"); env->ExceptionDescribe(); env->ExceptionClear(); return CHIP_ERROR_INCORRECT_STATE; } jint length = env->GetArrayLength(nifList); NetworkInterface * head = nullptr; for (jint i = 0; i < length; i++) { NetworkInterface * ifp = new NetworkInterface(); jobject nifObject = env->GetObjectArrayElement(nifList, i); jclass nifClass = env->GetObjectClass(nifObject); jfieldID getNameField = env->GetFieldID(nifClass, "name", "Ljava/lang/String;"); jstring jname = static_cast(env->GetObjectField(nifObject, getNameField)); if (jname != nullptr) { JniUtfString name(env, jname); Platform::CopyString(ifp->Name, name.c_str()); ifp->Name[Inet::InterfaceId::kMaxIfNameLength - 1] = '\0'; ifp->name = CharSpan(ifp->Name, strlen(ifp->Name)); } jfieldID isOperationalField = env->GetFieldID(nifClass, "isOperational", "Z"); ifp->isOperational = static_cast(env->GetBooleanField(nifObject, isOperationalField)); jfieldID getOpsrIPV4Field = env->GetFieldID(nifClass, "offPremiseServicesReachableIPv4", "Ljava/lang/Boolean;"); jobject opsrIPV4Obj = env->GetObjectField(nifObject, getOpsrIPV4Field); if (opsrIPV4Obj == nullptr) { ifp->offPremiseServicesReachableIPv4.SetNull(); } else { jboolean opsrIPV4 = JniReferences::GetInstance().BooleanToPrimitive(opsrIPV4Obj); ifp->offPremiseServicesReachableIPv4.SetNonNull(static_cast(opsrIPV4)); } jfieldID getOpsrIPV6Field = env->GetFieldID(nifClass, "offPremiseServicesReachableIPv6", "Ljava/lang/Boolean;"); jobject opsrIPV6Obj = env->GetObjectField(nifObject, getOpsrIPV6Field); if (opsrIPV6Obj == nullptr) { ifp->offPremiseServicesReachableIPv6.SetNull(); } else { jboolean opsrIPV6 = JniReferences::GetInstance().BooleanToPrimitive(opsrIPV6Obj); ifp->offPremiseServicesReachableIPv6.SetNonNull(static_cast(opsrIPV6)); } jfieldID gethardwareAddressField = env->GetFieldID(nifClass, "hardwareAddress", "[B"); jbyteArray jHardwareAddressObj = static_cast(env->GetObjectField(nifObject, gethardwareAddressField)); if (jHardwareAddressObj != nullptr) { size_t len = env->GetArrayLength(jHardwareAddressObj); len = (len > kMaxHardwareAddrSize) ? kMaxHardwareAddrSize : len; env->GetByteArrayRegion(jHardwareAddressObj, 0, static_cast(len), reinterpret_cast(ifp->MacAddress)); ifp->hardwareAddress = ByteSpan(ifp->MacAddress, 6); } jfieldID getTypeField = env->GetFieldID(nifClass, "type", "I"); ifp->type = static_cast(env->GetIntField(nifObject, getTypeField)); jfieldID ipv4AddressField = env->GetFieldID(nifClass, "ipv4Address", "[B"); jbyteArray jIpv4AddressObj = static_cast(env->GetObjectField(nifObject, ipv4AddressField)); if (jIpv4AddressObj != nullptr) { JniByteArray Ipv4ByteArray(env, jIpv4AddressObj); if (Ipv4ByteArray.size() == kMaxIPv4AddrSize) { memcpy(ifp->Ipv4AddressesBuffer[0], reinterpret_cast(Ipv4ByteArray.data()), kMaxIPv4AddrSize); ifp->Ipv4AddressSpans[0] = ByteSpan(ifp->Ipv4AddressesBuffer[0], kMaxIPv4AddrSize); ifp->IPv4Addresses = chip::app::DataModel::List(ifp->Ipv4AddressSpans, 1); } else { ChipLogError(DeviceLayer, "ipv4Address size (%d) not equal to kMaxIPv4AddrSize", Ipv4ByteArray.size()); } } jfieldID ipv6AddressField = env->GetFieldID(nifClass, "ipv6Address", "[B"); jbyteArray jIpv6AddressObj = static_cast(env->GetObjectField(nifObject, ipv6AddressField)); if (jIpv6AddressObj != nullptr) { JniByteArray Ipv6ByteArray(env, jIpv6AddressObj); if (Ipv6ByteArray.size() == kMaxIPv6AddrSize) { memcpy(ifp->Ipv6AddressesBuffer[0], reinterpret_cast(Ipv6ByteArray.data()), kMaxIPv6AddrSize); ifp->Ipv6AddressSpans[0] = ByteSpan(ifp->Ipv6AddressesBuffer[0], kMaxIPv6AddrSize); ifp->IPv6Addresses = chip::app::DataModel::List(ifp->Ipv6AddressSpans, 1); } else { ChipLogError(DeviceLayer, "ipv6Address size (%d) not equal to kMaxIPv6AddrSize", Ipv6ByteArray.size()); } } ifp->Next = head; head = ifp; } *netifpp = head; } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "ChannelManager::getChannelList status error: %s", err.AsString()); } return err; } void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp) { while (netifp) { NetworkInterface * del = netifp; netifp = netifp->Next; delete del; } } DiagnosticDataProvider & GetDiagnosticDataProviderImpl() { return DiagnosticDataProviderImpl::GetDefaultInstance(); } } // namespace DeviceLayer } // namespace chip