Add support for setsockoptBytes
Test: atest FrameworksNetTests:android.net.connectivity.android.net.NetworkUtilsTest
Change-Id: I3d94172fa8a42e2ab8ba4caf80d5caaa11fac703
diff --git a/framework/jni/android_net_NetworkUtils.cpp b/framework/jni/android_net_NetworkUtils.cpp
index ca297e5..5403be7 100644
--- a/framework/jni/android_net_NetworkUtils.cpp
+++ b/framework/jni/android_net_NetworkUtils.cpp
@@ -26,6 +26,7 @@
#include <bpf/BpfClassic.h>
#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
#include <nativehelper/JNIPlatformHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
#include <utils/Log.h>
#include "jni.h"
@@ -240,6 +241,15 @@
trw.rcv_wnd, trw.rcv_wup, tcpinfo.tcpi_rcv_wscale);
}
+static void android_net_utils_setsockoptBytes(JNIEnv *env, jclass clazz, jobject javaFd,
+ jint level, jint option, jbyteArray javaBytes) {
+ int sock = AFileDescriptor_getFd(env, javaFd);
+ ScopedByteArrayRO value(env, javaBytes);
+ if (setsockopt(sock, level, option, value.get(), value.size()) != 0) {
+ jniThrowErrnoException(env, "setsockoptBytes", errno);
+ }
+}
+
// ----------------------------------------------------------------------------
/*
@@ -260,6 +270,8 @@
{ "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
{ "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
+ { "setsockoptBytes", "(Ljava/io/FileDescriptor;II[B)V",
+ (void*) android_net_utils_setsockoptBytes},
};
// clang-format on
diff --git a/framework/src/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
index 2679b62..fbdc024 100644
--- a/framework/src/android/net/NetworkUtils.java
+++ b/framework/src/android/net/NetworkUtils.java
@@ -426,4 +426,16 @@
return routedIPCount;
}
+ /**
+ * Sets a socket option with byte array
+ *
+ * @param fd The socket file descriptor
+ * @param level The level at which the option is defined
+ * @param option The socket option for which the value is to be set
+ * @param value The option value to be set in byte array
+ * @throws ErrnoException if setsockopt fails
+ */
+ public static native void setsockoptBytes(FileDescriptor fd, int level, int option,
+ byte[] value) throws ErrnoException;
+
}
diff --git a/tests/unit/java/android/net/NetworkUtilsTest.java b/tests/unit/java/android/net/NetworkUtilsTest.java
index a28245d..5d789b4 100644
--- a/tests/unit/java/android/net/NetworkUtilsTest.java
+++ b/tests/unit/java/android/net/NetworkUtilsTest.java
@@ -16,19 +16,32 @@
package android.net;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_RCVTIMEO;
import static junit.framework.Assert.assertEquals;
import android.os.Build;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructTimeval;
import androidx.test.filters.SmallTest;
+import com.android.net.module.util.SocketUtils;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.TreeSet;
@RunWith(DevSdkIgnoreRunner.class)
@@ -131,4 +144,27 @@
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
NetworkUtils.routedIPv6AddressCount(set));
}
+
+ private byte[] getTimevalBytes(StructTimeval tv) {
+ byte[] timeval = new byte[16];
+ ByteBuffer buf = ByteBuffer.wrap(timeval);
+ buf.order(ByteOrder.nativeOrder());
+ buf.putLong(tv.tv_sec);
+ buf.putLong(tv.tv_usec);
+ return timeval;
+ }
+
+ @Test
+ public void testSetSockOptBytes() throws ErrnoException {
+ final FileDescriptor sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+ final StructTimeval writeTimeval = StructTimeval.fromMillis(1200);
+ byte[] timeval = getTimevalBytes(writeTimeval);
+ final StructTimeval readTimeval;
+
+ NetworkUtils.setsockoptBytes(sock, SOL_SOCKET, SO_RCVTIMEO, timeval);
+ readTimeval = Os.getsockoptTimeval(sock, SOL_SOCKET, SO_RCVTIMEO);
+
+ assertEquals(writeTimeval, readTimeval);
+ SocketUtils.closeSocketQuietly(sock);
+ }
}