From 3722189715f8aeac30d6672fe0fba46f37f147b2 Mon Sep 17 00:00:00 2001 From: Kevin Coppock <47542933+g-coppock@users.noreply.github.com> Date: Tue, 25 Jan 2022 22:32:15 -0600 Subject: [PATCH] Surface a NetworkLocation on Android for ChipDeviceController (#13797) Currently there is a method to getIpAddress(), but we also need to know the port. This adds a Java wrapper class that combines both properties, and the JNI bindings to resolve. Tested: - Commissioned an m5stack, and verified that the resolved NetworkLocation on the Java side matched Addr 0 logged from DIS after mDNS discovery completed. --- src/controller/java/BUILD.gn | 1 + .../java/CHIPDeviceController-JNI.cpp | 56 +++++++++++++++++++ .../ChipDeviceController.java | 12 ++++ .../devicecontroller/NetworkLocation.java | 28 ++++++++++ 4 files changed, 97 insertions(+) create mode 100644 src/controller/java/src/chip/devicecontroller/NetworkLocation.java diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index 4634ec9e53d520..7cc9543b5d254b 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -81,6 +81,7 @@ android_library("java") { "src/chip/devicecontroller/ChipDeviceControllerException.java", "src/chip/devicecontroller/GetConnectedDeviceCallbackJni.java", "src/chip/devicecontroller/NetworkCredentials.java", + "src/chip/devicecontroller/NetworkLocation.java", "src/chip/devicecontroller/PaseVerifierParams.java", "zap-generated/chip/devicecontroller/ChipClusters.java", "zap-generated/chip/devicecontroller/ChipStructs.java", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 41d4d6e074d747..7b2969fbee23b4 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -62,6 +62,7 @@ using namespace chip::Controller; static void * IOThreadMain(void * arg); static CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jint passcodeId, jbyteArray pakeVerifier, jobject & outParams); +static CHIP_ERROR N2J_NetworkLocation(JNIEnv * env, jstring ipAddress, jint port, jobject & outLocation); namespace { @@ -450,6 +451,40 @@ JNI_METHOD(jstring, getIpAddress)(JNIEnv * env, jobject self, jlong handle, jlon return env->NewStringUTF(addrStr); } +JNI_METHOD(jobject, getNetworkLocation)(JNIEnv * env, jobject self, jlong handle, jlong deviceId) +{ + chip::DeviceLayer::StackLock lock; + AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); + + chip::Inet::IPAddress addr; + uint16_t port; + jobject networkLocation; + char addrStr[50]; + + CHIP_ERROR err = + wrapper->Controller()->GetPeerAddressAndPort(PeerId() + .SetCompressedFabricId(wrapper->Controller()->GetCompressedFabricId()) + .SetNodeId(static_cast(deviceId)), + addr, port); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "Failed to get device address."); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); + } + + addr.ToString(addrStr); + + err = N2J_NetworkLocation(env, env->NewStringUTF(addrStr), static_cast(port), networkLocation); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "Failed to create NetworkLocation"); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); + } + + return networkLocation; +} + JNI_METHOD(jlong, getCompressedFabricId)(JNIEnv * env, jobject self, jlong handle) { chip::DeviceLayer::StackLock lock; @@ -621,3 +656,24 @@ CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jint passcod exit: return err; } + +CHIP_ERROR N2J_NetworkLocation(JNIEnv * env, jstring ipAddress, jint port, jobject & outLocation) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + jmethodID constructor; + jclass locationClass; + + err = JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/NetworkLocation", locationClass); + JniClass networkLocationClass(locationClass); + SuccessOrExit(err); + + env->ExceptionClear(); + constructor = env->GetMethodID(locationClass, "", "(Ljava/lang/String;I)V"); + VerifyOrExit(constructor != nullptr, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND); + + outLocation = (jobject) env->NewObject(locationClass, constructor, ipAddress, port); + + VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN); +exit: + return err; +} diff --git a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java index 5f85dede15a222..a30931195712eb 100644 --- a/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java +++ b/src/controller/java/src/chip/devicecontroller/ChipDeviceController.java @@ -259,6 +259,16 @@ public String getIpAddress(long deviceId) { return getIpAddress(deviceControllerPtr, deviceId); } + /** + * Returns the {@link NetworkLocation} at which the given {@code deviceId} has been found. + * + * @param deviceId the 64-bit node ID of the device + * @throws ChipDeviceControllerException if the device location could not be resolved + */ + public NetworkLocation getNetworkLocation(long deviceId) { + return getNetworkLocation(deviceControllerPtr, deviceId); + } + public long getCompressedFabricId() { return getCompressedFabricId(deviceControllerPtr); } @@ -346,6 +356,8 @@ private native void getConnectedDevicePointer( private native String getIpAddress(long deviceControllerPtr, long deviceId); + private native NetworkLocation getNetworkLocation(long deviceControllerPtr, long deviceId); + private native long getCompressedFabricId(long deviceControllerPtr); private native void updateDevice(long deviceControllerPtr, long fabricId, long deviceId); diff --git a/src/controller/java/src/chip/devicecontroller/NetworkLocation.java b/src/controller/java/src/chip/devicecontroller/NetworkLocation.java new file mode 100644 index 00000000000000..2f1380f98d8e96 --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/NetworkLocation.java @@ -0,0 +1,28 @@ +package chip.devicecontroller; + +import java.util.Locale; + +/** Represents a location on an operational network. */ +public final class NetworkLocation { + private final String ipAddress; + private final int port; + + public NetworkLocation(String ipAddress, int port) { + this.ipAddress = ipAddress; + this.port = port; + } + + /** Returns the IP address (e.g. fe80::3e61:5ff:fe0c:89f8). */ + public String getIpAddress() { + return ipAddress; + } + + public int getPort() { + return port; + } + + @Override + public String toString() { + return String.format(Locale.ROOT, "%s[%d]", ipAddress, port); + } +}