| /* |
| * |
| * 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 <cstddef> |
| #include <cstring> |
| #include <jni.h> |
| #include <platform/internal/CHIPDeviceLayerInternal.h> |
| |
| #include "DiagnosticDataProviderImpl.h" |
| #include <lib/support/CHIPJNIError.h> |
| #include <lib/support/CHIPMem.h> |
| #include <lib/support/CHIPMemString.h> |
| #include <lib/support/JniTypeWrappers.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| #include <platform/DiagnosticDataProvider.h> |
| #include <unistd.h> |
| |
| 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<uint16_t>(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<jstring>(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<bool>(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<bool>(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<bool>(opsrIPV6)); |
| } |
| |
| jfieldID gethardwareAddressField = env->GetFieldID(nifClass, "hardwareAddress", "[B"); |
| jbyteArray jHardwareAddressObj = static_cast<jbyteArray>(env->GetObjectField(nifObject, gethardwareAddressField)); |
| if (jHardwareAddressObj != nullptr) |
| { |
| size_t len = env->GetArrayLength(jHardwareAddressObj); |
| len = (len > kMaxHardwareAddrSize) ? kMaxHardwareAddrSize : len; |
| env->GetByteArrayRegion(jHardwareAddressObj, 0, static_cast<uint32_t>(len), |
| reinterpret_cast<jbyte *>(ifp->MacAddress)); |
| ifp->hardwareAddress = ByteSpan(ifp->MacAddress, 6); |
| } |
| |
| jfieldID getTypeField = env->GetFieldID(nifClass, "type", "I"); |
| ifp->type = static_cast<InterfaceTypeEnum>(env->GetIntField(nifObject, getTypeField)); |
| |
| jfieldID ipv4AddressField = env->GetFieldID(nifClass, "ipv4Address", "[B"); |
| jbyteArray jIpv4AddressObj = static_cast<jbyteArray>(env->GetObjectField(nifObject, ipv4AddressField)); |
| if (jIpv4AddressObj != nullptr) |
| { |
| JniByteArray Ipv4ByteArray(env, jIpv4AddressObj); |
| |
| if (Ipv4ByteArray.size() == kMaxIPv4AddrSize) |
| { |
| memcpy(ifp->Ipv4AddressesBuffer[0], reinterpret_cast<const uint8_t *>(Ipv4ByteArray.data()), kMaxIPv4AddrSize); |
| ifp->Ipv4AddressSpans[0] = ByteSpan(ifp->Ipv4AddressesBuffer[0], kMaxIPv4AddrSize); |
| ifp->IPv4Addresses = chip::app::DataModel::List<chip::ByteSpan>(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<jbyteArray>(env->GetObjectField(nifObject, ipv6AddressField)); |
| if (jIpv6AddressObj != nullptr) |
| { |
| JniByteArray Ipv6ByteArray(env, jIpv6AddressObj); |
| |
| if (Ipv6ByteArray.size() == kMaxIPv6AddrSize) |
| { |
| memcpy(ifp->Ipv6AddressesBuffer[0], reinterpret_cast<const uint8_t *>(Ipv6ByteArray.data()), kMaxIPv6AddrSize); |
| ifp->Ipv6AddressSpans[0] = ByteSpan(ifp->Ipv6AddressesBuffer[0], kMaxIPv6AddrSize); |
| ifp->IPv6Addresses = chip::app::DataModel::List<chip::ByteSpan>(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 |