Merge "Map available JCA algorithms and availability in javadoc"
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ObservableTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ObservableTest.java
index b13a876..fcd9e2f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ObservableTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ObservableTest.java
@@ -20,6 +20,7 @@
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
+import java.util.concurrent.atomic.AtomicReference;
public class ObservableTest extends junit.framework.TestCase {
@@ -229,6 +230,24 @@
.elementAt(0).equals(obj));
}
+ static final class AlwaysChangedObservable extends Observable {
+ @Override
+ public boolean hasChanged() {
+ return true;
+ }
+ }
+
+ // http://b/28797950
+ public void test_observableWithOverridenHasChanged() throws Exception {
+ final AtomicReference<Observable> updated = new AtomicReference<>();
+ final Observer observer = (observable1, data) -> updated.set(observable1);
+
+ Observable alwaysChanging = new AlwaysChangedObservable();
+ alwaysChanging.addObserver(observer);
+ alwaysChanging.notifyObservers(null);
+ assertSame(alwaysChanging, updated.get());
+ }
+
/**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index fbf8939..854e34e 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -99,8 +99,10 @@
public int getxattr(String path, String name, byte[] outValue) throws ErrnoException { return os.getxattr(path, name, outValue); }
public String if_indextoname(int index) { return os.if_indextoname(index); }
public InetAddress inet_pton(int family, String address) { return os.inet_pton(family, address); }
+ public int ioctlFlags(FileDescriptor fd, String interfaceName) throws ErrnoException { return os.ioctlFlags(fd, interfaceName); };
public InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException { return os.ioctlInetAddress(fd, cmd, interfaceName); }
public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException { return os.ioctlInt(fd, cmd, arg); }
+ public int ioctlMTU(FileDescriptor fd, String interfaceName) throws ErrnoException { return os.ioctlMTU(fd, interfaceName); };
public boolean isatty(FileDescriptor fd) { return os.isatty(fd); }
public void kill(int pid, int signal) throws ErrnoException { os.kill(pid, signal); }
public void lchown(String path, int uid, int gid) throws ErrnoException { os.lchown(path, uid, gid); }
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index 006a29e..3f6d2b1 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -91,8 +91,10 @@
public int getxattr(String path, String name, byte[] outValue) throws ErrnoException;
public String if_indextoname(int index);
public InetAddress inet_pton(int family, String address);
+ public int ioctlFlags(FileDescriptor fd, String interfaceName) throws ErrnoException;
public InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException;
public int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException;
+ public int ioctlMTU(FileDescriptor fd, String interfaceName) throws ErrnoException;
public boolean isatty(FileDescriptor fd);
public void kill(int pid, int signal) throws ErrnoException;
public void lchown(String path, int uid, int gid) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index a341641..46f33e5 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -93,8 +93,10 @@
public native int getxattr(String path, String name, byte[] outValue) throws ErrnoException;
public native String if_indextoname(int index);
public native InetAddress inet_pton(int family, String address);
+ public native int ioctlFlags(FileDescriptor fd, String interfaceName) throws ErrnoException;
public native InetAddress ioctlInetAddress(FileDescriptor fd, int cmd, String interfaceName) throws ErrnoException;
public native int ioctlInt(FileDescriptor fd, int cmd, MutableInt arg) throws ErrnoException;
+ public native int ioctlMTU(FileDescriptor fd, String interfaceName) throws ErrnoException;
public native boolean isatty(FileDescriptor fd);
public native void kill(int pid, int signal) throws ErrnoException;
public native void lchown(String path, int uid, int gid) throws ErrnoException;
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 5d7e42d..3c8d7ce 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -1210,6 +1210,16 @@
return sockaddrToInetAddress(env, ss, NULL);
}
+static jint Posix_ioctlFlags(JNIEnv* env, jobject, jobject javaFd, jstring javaInterfaceName) {
+ struct ifreq req;
+ if (!fillIfreq(env, javaInterfaceName, req)) {
+ return 0;
+ }
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, SIOCGIFFLAGS, &req)));
+ return req.ifr_flags;
+}
+
static jobject Posix_ioctlInetAddress(JNIEnv* env, jobject, jobject javaFd, jint cmd, jstring javaInterfaceName) {
struct ifreq req;
if (!fillIfreq(env, javaInterfaceName, req)) {
@@ -1236,6 +1246,16 @@
return rc;
}
+static jint Posix_ioctlMTU(JNIEnv* env, jobject, jobject javaFd, jstring javaInterfaceName) {
+ struct ifreq req;
+ if (!fillIfreq(env, javaInterfaceName, req)) {
+ return 0;
+ }
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, SIOCGIFMTU, &req)));
+ return req.ifr_mtu;
+}
+
static jboolean Posix_isatty(JNIEnv* env, jobject, jobject javaFd) {
int fd = jniGetFDFromFileDescriptor(env, javaFd);
return TEMP_FAILURE_RETRY(isatty(fd)) == 1;
@@ -2010,8 +2030,10 @@
NATIVE_METHOD(Posix, getxattr, "(Ljava/lang/String;Ljava/lang/String;[B)I"),
NATIVE_METHOD(Posix, if_indextoname, "(I)Ljava/lang/String;"),
NATIVE_METHOD(Posix, inet_pton, "(ILjava/lang/String;)Ljava/net/InetAddress;"),
+ NATIVE_METHOD(Posix, ioctlFlags, "(Ljava/io/FileDescriptor;Ljava/lang/String;)I"),
NATIVE_METHOD(Posix, ioctlInetAddress, "(Ljava/io/FileDescriptor;ILjava/lang/String;)Ljava/net/InetAddress;"),
NATIVE_METHOD(Posix, ioctlInt, "(Ljava/io/FileDescriptor;ILandroid/util/MutableInt;)I"),
+ NATIVE_METHOD(Posix, ioctlMTU, "(Ljava/io/FileDescriptor;Ljava/lang/String;)I"),
NATIVE_METHOD(Posix, isatty, "(Ljava/io/FileDescriptor;)Z"),
NATIVE_METHOD(Posix, kill, "(II)V"),
NATIVE_METHOD(Posix, lchown, "(Ljava/lang/String;II)V"),
diff --git a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
index a3f9065..49b3ad1 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
@@ -16,7 +16,10 @@
package libcore.java.lang.reflect;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
import junit.framework.TestCase;
@@ -226,14 +229,320 @@
private void a() {}
public static void b() {}
}
- public static interface InterfaceA {
+ public interface InterfaceA {
void a();
}
public static abstract class Sub extends Super implements InterfaceA {
}
- public static interface InterfaceB extends InterfaceA {}
- public static interface InterfaceC extends InterfaceB {}
+ public interface InterfaceB extends InterfaceA {}
+ public interface InterfaceC extends InterfaceB {}
public static abstract class ImplementsC implements InterfaceC {}
public static abstract class ExtendsImplementsC extends ImplementsC {}
+
+ // Static interface method reflection.
+
+ public interface InterfaceWithStatic {
+ static String staticMethod() {
+ return identifyCaller();
+ }
+ }
+
+ public void testStaticInterfaceMethod_getMethod() throws Exception {
+ Method method = InterfaceWithStatic.class.getMethod("staticMethod");
+ assertFalse(method.isDefault());
+ assertEquals(Modifier.PUBLIC | Modifier.STATIC, method.getModifiers());
+ assertEquals(InterfaceWithStatic.class, method.getDeclaringClass());
+ }
+
+ public void testStaticInterfaceMethod_getDeclaredMethod() throws Exception {
+ Method declaredMethod = InterfaceWithStatic.class.getDeclaredMethod("staticMethod");
+ assertFalse(declaredMethod.isDefault());
+ assertEquals(Modifier.PUBLIC | Modifier.STATIC, declaredMethod.getModifiers());
+ assertEquals(InterfaceWithStatic.class, declaredMethod.getDeclaringClass());
+ }
+
+ public void testStaticInterfaceMethod_invoke() throws Exception {
+ String interfaceWithStaticClassName = InterfaceWithStatic.class.getName();
+ assertEquals(interfaceWithStaticClassName, InterfaceWithStatic.staticMethod());
+
+ Method method = InterfaceWithStatic.class.getMethod("staticMethod");
+ assertEquals(interfaceWithStaticClassName, method.invoke(null));
+ assertEquals(interfaceWithStaticClassName, method.invoke(new InterfaceWithStatic() {}));
+ }
+
+ public void testStaticInterfaceMethod_setAccessible() throws Exception {
+ String interfaceWithStaticClassName = InterfaceWithStatic.class.getName();
+ Method method = InterfaceWithStatic.class.getMethod("staticMethod");
+ method.setAccessible(false);
+ // No effect expected.
+ assertEquals(interfaceWithStaticClassName, method.invoke(null));
+ }
+
+ // Default method reflection.
+
+ public interface InterfaceWithDefault {
+ default String defaultMethod() {
+ return identifyCaller();
+ }
+ }
+
+ public static class ImplementationWithDefault implements InterfaceWithDefault {
+ }
+
+ public void testDefaultMethod_getDeclaredMethod_interface() throws Exception {
+ Class<InterfaceWithDefault> interfaceWithDefaultClass = InterfaceWithDefault.class;
+ Method defaultMethod = interfaceWithDefaultClass.getDeclaredMethod("defaultMethod");
+ assertEquals(InterfaceWithDefault.class, defaultMethod.getDeclaringClass());
+ assertTrue(defaultMethod.isDefault());
+ }
+
+ public void testDefaultMethod_inheritance() throws Exception {
+ Class<InterfaceWithDefault> interfaceWithDefaultClass = InterfaceWithDefault.class;
+ String interfaceWithDefaultClassName = interfaceWithDefaultClass.getName();
+ Method defaultMethod = interfaceWithDefaultClass.getDeclaredMethod("defaultMethod");
+
+ InterfaceWithDefault anon = new InterfaceWithDefault() {};
+ Class<?> anonClass = anon.getClass();
+ Method inheritedDefaultMethod = anonClass.getMethod("defaultMethod");
+ assertEquals(inheritedDefaultMethod, defaultMethod);
+
+ // Check invocation behavior.
+ assertEquals(interfaceWithDefaultClassName, defaultMethod.invoke(anon));
+ assertEquals(interfaceWithDefaultClassName, inheritedDefaultMethod.invoke(anon));
+ assertEquals(interfaceWithDefaultClassName, anon.defaultMethod());
+
+ // Check other method properties.
+ assertEquals(InterfaceWithDefault.class, inheritedDefaultMethod.getDeclaringClass());
+ assertTrue(inheritedDefaultMethod.isDefault());
+
+ // Confirm the method is not considered declared on the anonymous class.
+ assertNull(getDeclaredMethodOrNull(anonClass, "defaultMethod"));
+ }
+
+ public void testDefaultMethod_override() throws Exception {
+ Class<InterfaceWithDefault> interfaceWithDefaultClass = InterfaceWithDefault.class;
+ Method defaultMethod = interfaceWithDefaultClass.getDeclaredMethod("defaultMethod");
+
+ InterfaceWithDefault anon = new InterfaceWithDefault() {
+ @Override public String defaultMethod() {
+ return identifyCaller();
+ }
+ };
+
+ Class<? extends InterfaceWithDefault> anonClass = anon.getClass();
+ String anonymousClassName = anonClass.getName();
+
+ Method overriddenDefaultMethod = getDeclaredMethodOrNull(anonClass, "defaultMethod");
+ assertNotNull(overriddenDefaultMethod);
+ assertFalse(overriddenDefaultMethod.equals(defaultMethod));
+
+ // Check invocation behavior.
+ assertEquals(anonymousClassName, defaultMethod.invoke(anon));
+ assertEquals(anonymousClassName, overriddenDefaultMethod.invoke(anon));
+ assertEquals(anonymousClassName, anon.defaultMethod());
+
+ // Check other method properties.
+ assertEquals(anonClass, overriddenDefaultMethod.getDeclaringClass());
+ assertFalse(overriddenDefaultMethod.isDefault());
+ }
+
+ public void testDefaultMethod_setAccessible() throws Exception {
+ InterfaceWithDefault anon = new InterfaceWithDefault() {};
+
+ Method defaultMethod = anon.getClass().getMethod("defaultMethod");
+ defaultMethod.setAccessible(false);
+ // setAccessible(false) should have no effect.
+ assertEquals(InterfaceWithDefault.class.getName(), defaultMethod.invoke(anon));
+
+ InterfaceWithDefault anon2 = new InterfaceWithDefault() {
+ @Override public String defaultMethod() {
+ return identifyCaller();
+ }
+ };
+
+ Class<? extends InterfaceWithDefault> anon2Class = anon2.getClass();
+ Method overriddenDefaultMethod = anon2Class.getDeclaredMethod("defaultMethod");
+ overriddenDefaultMethod.setAccessible(false);
+ // setAccessible(false) should have no effect.
+ assertEquals(anon2Class.getName(), overriddenDefaultMethod.invoke(anon2));
+ }
+
+ interface InterfaceWithReAbstractedMethod extends InterfaceWithDefault {
+ // Re-abstract a default method.
+ @Override String defaultMethod();
+ }
+
+ public void testDefaultMethod_reabstracted() throws Exception {
+ Class<InterfaceWithReAbstractedMethod> subclass = InterfaceWithReAbstractedMethod.class;
+
+ Method reabstractedDefaultMethod = subclass.getMethod("defaultMethod");
+ assertFalse(reabstractedDefaultMethod.isDefault());
+ assertEquals(reabstractedDefaultMethod, subclass.getDeclaredMethod("defaultMethod"));
+ assertEquals(subclass, reabstractedDefaultMethod.getDeclaringClass());
+ }
+
+ public void testDefaultMethod_reimplementedInClass() throws Exception {
+ InterfaceWithDefault impl = new InterfaceWithReAbstractedMethod() {
+ // Implement a reabstracted default method.
+ @Override public String defaultMethod() {
+ return identifyCaller();
+ }
+ };
+ Class<?> implClass = impl.getClass();
+ String implClassName = implClass.getName();
+
+ Method implClassDefaultMethod = getDeclaredMethodOrNull(implClass, "defaultMethod");
+ assertEquals(implClassDefaultMethod, implClass.getMethod("defaultMethod"));
+
+ // Check invocation behavior.
+ assertEquals(implClassName, impl.defaultMethod());
+ assertEquals(implClassName, implClassDefaultMethod.invoke(impl));
+
+ // Check other method properties.
+ assertEquals(implClass, implClassDefaultMethod.getDeclaringClass());
+ assertFalse(implClassDefaultMethod.isDefault());
+ }
+
+ interface InterfaceWithRedefinedMethods extends InterfaceWithReAbstractedMethod {
+ // Reimplement an abstracted default method.
+ @Override default String defaultMethod() {
+ return identifyCaller();
+ }
+ }
+
+ public void testDefaultMethod_reimplementInInterface() throws Exception {
+ Class<?> interfaceClass = InterfaceWithRedefinedMethods.class;
+ String interfaceClassName = interfaceClass.getName();
+
+ // NOTE: The line below defines an anonymous class that implements
+ // InterfaceWithReDefinedMethods (and does not need to provide any declarations).
+ // See the {}.
+ InterfaceWithDefault impl = new InterfaceWithRedefinedMethods() {};
+ Class<?> implClass = impl.getClass();
+
+ Method implClassDefaultMethod = implClass.getMethod("defaultMethod");
+ assertNull(getDeclaredMethodOrNull(implClass, "defaultMethod"));
+
+ // Check invocation behavior.
+ assertEquals(interfaceClassName, impl.defaultMethod());
+ assertEquals(interfaceClassName, implClassDefaultMethod.invoke(impl));
+
+ // Check other method properties.
+ assertEquals(interfaceClass, implClassDefaultMethod.getDeclaringClass());
+ assertTrue(implClassDefaultMethod.isDefault());
+ }
+
+ public void testDefaultMethod_invoke() throws Exception {
+ InterfaceWithDefault impl1 = new InterfaceWithRedefinedMethods() {};
+ InterfaceWithDefault impl2 = new InterfaceWithReAbstractedMethod() {
+ @Override public String defaultMethod() {
+ return identifyCaller();
+ }
+ };
+ InterfaceWithDefault impl3 = new InterfaceWithDefault() {};
+
+ Class[] classes = {
+ InterfaceWithRedefinedMethods.class,
+ impl1.getClass(),
+ InterfaceWithReAbstractedMethod.class,
+ impl2.getClass(),
+ InterfaceWithDefault.class,
+ impl3.getClass(),
+ };
+ Object[] instances = { impl1, impl2, impl3 };
+
+ // Attempt to invoke all declarations of defaultMethod() on a selection of instances.
+ for (Class<?> clazz : classes) {
+ Method method = clazz.getMethod("defaultMethod");
+ for (Object instance : instances) {
+ if (method.getDeclaringClass().isAssignableFrom(instance.getClass())) {
+ Method trueMethod = instance.getClass().getMethod("defaultMethod");
+ // All implementations of defaultMethod return the class where the method is
+ // declared, enabling us to tell if the correct implementation has been called.
+ Class<?> declaringClass = trueMethod.getDeclaringClass();
+ assertEquals(declaringClass.getName(), method.invoke(instance));
+ } else {
+ try {
+ method.invoke(instance);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+ }
+ }
+ }
+
+ interface OtherInterfaceWithDefault {
+ default String defaultMethod() {
+ return identifyCaller();
+ }
+ }
+
+ public void testDefaultMethod_superSyntax() throws Exception {
+ class ImplementationSuperUser implements InterfaceWithDefault, OtherInterfaceWithDefault {
+ @Override public String defaultMethod() {
+ return identifyCaller() + ":" +
+ InterfaceWithDefault.super.defaultMethod() + ":" +
+ OtherInterfaceWithDefault.super.defaultMethod();
+ }
+ }
+
+ String implementationSuperUserClassName = ImplementationSuperUser.class.getName();
+ String interfaceWithDefaultClassName = InterfaceWithDefault.class.getName();
+ String otherInterfaceWithDefaultClassName = OtherInterfaceWithDefault.class.getName();
+ String expectedReturnValue = implementationSuperUserClassName + ":" +
+ interfaceWithDefaultClassName + ":" + otherInterfaceWithDefaultClassName;
+ ImplementationSuperUser obj = new ImplementationSuperUser();
+ assertEquals(expectedReturnValue, obj.defaultMethod());
+
+ Method defaultMethod = ImplementationSuperUser.class.getMethod("defaultMethod");
+ assertEquals(expectedReturnValue, defaultMethod.invoke(obj));
+ }
+
+ public void testProxyWithDefaultMethods() throws Exception {
+ InvocationHandler invocationHandler = new InvocationHandler() {
+ @Override public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ assertSame(InterfaceWithDefault.class, method.getDeclaringClass());
+ return identifyCaller();
+ }
+ };
+
+ InterfaceWithDefault proxyWithDefaultMethod = (InterfaceWithDefault) Proxy.newProxyInstance(
+ Thread.currentThread().getContextClassLoader(),
+ new Class[] { InterfaceWithDefault.class },
+ invocationHandler);
+ String invocationHandlerClassName = invocationHandler.getClass().getName();
+
+ // Check the proxy implements the default method.
+ Class<? extends InterfaceWithDefault> proxyClass = proxyWithDefaultMethod.getClass();
+ Method defaultMethod = proxyClass.getMethod("defaultMethod");
+ assertEquals(proxyClass, defaultMethod.getDeclaringClass());
+ assertFalse(defaultMethod.isDefault());
+
+ // The default method is intercepted like anything else.
+ assertEquals(invocationHandlerClassName, proxyWithDefaultMethod.defaultMethod());
+ }
+
+ private static Method getDeclaredMethodOrNull(Class<?> clazz, String methodName) {
+ try {
+ Method m = clazz.getDeclaredMethod(methodName);
+ assertNotNull(m);
+ return m;
+ } catch (NoSuchMethodException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Keep this package-protected or public to avoid the introduction of synthetic methods that
+ * throw off the offset.
+ */
+ static String identifyCaller() {
+ StackTraceElement[] stack = Thread.currentThread().getStackTrace();
+ int i = 0;
+ while (!stack[i++].getMethodName().equals("identifyCaller")) {}
+ return stack[i].getClassName();
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/MembershipKeyTest.java b/luni/src/test/java/libcore/java/nio/channels/MembershipKeyTest.java
new file mode 100644
index 0000000..18dc615
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/channels/MembershipKeyTest.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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
+ */
+
+package libcore.java.nio.channels;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.StandardProtocolFamily;
+import java.net.StandardSocketOptions;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.MembershipKey;
+import java.util.Enumeration;
+
+public class MembershipKeyTest extends TestCase {
+
+ private MembershipKey key;
+ private MembershipKey keyWithSource;
+ private final int PORT = 5000;
+ private final String TEST_MESSAGE = "hello";
+ private DatagramChannel client;
+ private InetAddress sourceAddress = Inet4Address.LOOPBACK;
+ private final static InetAddress MULTICAST_ADDRESS = getMulticastAddress();
+ private final static NetworkInterface NETWORK_INTERFACE = getNetworkInterface();
+
+ private void setup(boolean withSource) throws Exception {
+ client = DatagramChannel.open(StandardProtocolFamily.INET)
+ .bind(new InetSocketAddress(Inet4Address.ANY, PORT));
+ client.configureBlocking(false);
+
+ if (withSource) {
+ keyWithSource = client.join(MULTICAST_ADDRESS, NETWORK_INTERFACE, sourceAddress);
+ } else {
+ key = client.join(MULTICAST_ADDRESS, NETWORK_INTERFACE);
+ }
+ }
+
+ @Override
+ public void tearDown() throws IOException {
+ client.close();
+ key = null;
+ }
+
+ public void test_isValid_OnChannelCloseWithJoinWithoutSource() throws Exception {
+ setup(false);
+ test_isValid();
+ }
+
+ public void test_isValid_OnChannelCloseWithJoinWithSource() throws Exception {
+ setup(true);
+ test_isValid();
+ }
+
+ private void test_isValid() throws IOException {
+ assertTrue(key.isValid());
+ client.close();
+ assertFalse(key.isValid());
+ }
+
+ public void test_isValid_OnDropJoinWithoutSource() throws Exception {
+ setup(false);
+ test_isValid_OnDrop();
+ }
+
+ public void test_isValid_OnDropJoinWithSource() throws Exception {
+ setup(true);
+ test_isValid_OnDrop();
+ }
+
+ private void test_isValid_OnDrop() {
+ assertTrue(key.isValid());
+ key.drop();
+ assertFalse(key.isValid());
+ }
+
+ public void test_dropWithJoinWithoutSource() throws Exception {
+ setup(false);
+ test_drop();
+ }
+
+ public void test_dropWithJoinWithSource() throws Exception {
+ setup(true);
+ test_drop();
+ }
+
+ private void test_drop() throws IOException {
+ key.drop();
+ try(DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
+ assertEquals(TEST_MESSAGE.length(), dc
+ .bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0))
+ .send(ByteBuffer.wrap(TEST_MESSAGE.getBytes()),
+ new InetSocketAddress(MULTICAST_ADDRESS, PORT)));
+ }
+
+ ByteBuffer buffer = ByteBuffer.allocate(1048);
+ client.receive(buffer);
+ buffer.flip();
+ assertEquals(0, buffer.limit());
+ }
+
+ public void test_networkInterface() throws Exception {
+ setup(false);
+ assertEquals(NETWORK_INTERFACE, key.networkInterface());
+ client.close();
+ assertEquals(NETWORK_INTERFACE, key.networkInterface());
+ }
+
+ public void test_sourceAddressWithJoinWithSource() throws Exception {
+ setup(true);
+ assertEquals(sourceAddress, key.sourceAddress());
+ }
+
+ public void test_sourceAddressWithJoinWithoutSource() throws Exception {
+ setup(false);
+ assertNull(key.sourceAddress());
+ }
+
+ public void test_groupWithJoinWithSource() throws Exception {
+ setup(true);
+ assertEquals(MULTICAST_ADDRESS, key.group());
+ }
+
+ public void test_groupWithoutJoinWIthSource() throws Exception {
+ setup(false);
+ assertEquals(MULTICAST_ADDRESS, key.group());
+ }
+
+ public void test_channelWithJoinWithSource() throws Exception {
+ setup(true);
+ assertEquals(client, key.channel());
+ key.drop();
+ assertEquals(client, key.channel());
+ }
+
+ public void test_channelWithJoinWithoutSource() throws Exception {
+ setup(false);
+ assertEquals(client, key.channel());
+ key.drop();
+ assertEquals(client, key.channel());
+ }
+
+ public void test_blockWithJoinWithSource() throws Exception {
+ setup(true);
+ try {
+ key.block(sourceAddress);
+ fail();
+ } catch (IllegalStateException expected) {}
+ }
+
+ public void test_blockWithJoinWithoutSource() throws Exception {
+ setup(false);
+ key.block(sourceAddress);
+
+ try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
+ assertEquals(TEST_MESSAGE.length(), dc
+ .bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0))
+ .send(ByteBuffer.wrap(TEST_MESSAGE.getBytes()),
+ new InetSocketAddress(MULTICAST_ADDRESS, PORT)));
+ }
+
+ ByteBuffer buffer = ByteBuffer.allocate(1048);
+ client.receive(buffer);
+ buffer.flip();
+ assertEquals(0, buffer.limit());
+ }
+
+ public void test_block_Exception () throws Exception {
+ setup(false);
+
+ // Blocking a multicast channel
+ try {
+ key.block(Inet4Address.getByName("224.0.0.10"));
+ } catch (IllegalArgumentException expected) {}
+
+ // Different address type than the group
+ try {
+ key.block(Inet6Address.LOOPBACK);
+ } catch (IllegalArgumentException expected) {}
+
+ key.drop();
+ try {
+ key.block(sourceAddress);
+ } catch (IllegalStateException expected) {}
+ }
+
+ public void test_unblockWithJoinWithSource() throws Exception {
+ setup(true);
+ try {
+ key.unblock(Inet4Address.getByName("127.0.0.2"));
+ } catch (IllegalStateException expected) {}
+ }
+
+ public void test_unblockWithJoinWithoutSource() throws Exception {
+ setup(false);
+
+ key.block(sourceAddress);
+ key.unblock(sourceAddress);
+
+ try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
+ assertEquals(TEST_MESSAGE.length(), dc
+ .bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0))
+ .setOption(StandardSocketOptions.IP_MULTICAST_LOOP, true /* enable loop */)
+ .send(ByteBuffer.wrap(TEST_MESSAGE.getBytes()),
+ new InetSocketAddress(MULTICAST_ADDRESS, PORT)));
+ }
+
+ ByteBuffer buffer = ByteBuffer.allocate(1048);
+ client.receive(buffer);
+ buffer.flip();
+ int limits = buffer.limit();
+ byte bytes[] = new byte[limits];
+ buffer.get(bytes, 0, limits);
+ String receivedMessage = new String(bytes);
+ assertEquals(TEST_MESSAGE, receivedMessage);
+ }
+
+ public void test_unblock_Exception() throws Exception {
+ setup(false);
+ try {
+ key.unblock(sourceAddress);
+ } catch (IllegalStateException expected) {}
+
+ key.drop();
+
+ try {
+ key.unblock(sourceAddress);
+ } catch (IllegalStateException expected) {}
+ }
+
+ private static InetAddress getMulticastAddress() {
+ try {
+ return InetAddress.getByName("239.255.0.1");
+ } catch (UnknownHostException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ private static NetworkInterface getNetworkInterface() {
+ try {
+ return NetworkInterface.getByName("lo");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/ojluni/src/main/java/java/net/NetworkInterface.java b/ojluni/src/main/java/java/net/NetworkInterface.java
index edae4b3..3ea67be 100755
--- a/ojluni/src/main/java/java/net/NetworkInterface.java
+++ b/ojluni/src/main/java/java/net/NetworkInterface.java
@@ -25,11 +25,19 @@
package java.net;
+import android.system.ErrnoException;
+
+import java.io.FileDescriptor;
import java.util.Enumeration;
import java.util.NoSuchElementException;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
import sun.security.action.*;
import java.security.AccessController;
+import static android.system.OsConstants.*;
+
/**
* This class represents a Network Interface made up of a name,
* and a list of IP addresses assigned to this interface.
@@ -374,7 +382,7 @@
*/
public boolean isUp() throws SocketException {
- return isUp0(name, index);
+ return (getFlags() & IFF_UP) != 0;
}
/**
@@ -386,7 +394,7 @@
*/
public boolean isLoopback() throws SocketException {
- return isLoopback0(name, index);
+ return (getFlags() & IFF_LOOPBACK) != 0;
}
/**
@@ -401,7 +409,7 @@
*/
public boolean isPointToPoint() throws SocketException {
- return isP2P0(name, index);
+ return (getFlags() & IFF_POINTOPOINT) != 0;
}
/**
@@ -413,7 +421,7 @@
*/
public boolean supportsMulticast() throws SocketException {
- return supportsMulticast0(name, index);
+ return (getFlags() & IFF_MULTICAST) != 0;
}
/**
@@ -442,7 +450,17 @@
* @since 1.6
*/
public int getMTU() throws SocketException {
- return getMTU0(name, index);
+ FileDescriptor fd = null;
+ try {
+ fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
+ return Libcore.os.ioctlMTU(fd, name);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsSocketException();
+ } catch (Exception ex) {
+ throw new SocketException(ex);
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
}
/**
@@ -462,11 +480,19 @@
return virtual;
}
- private native static boolean isUp0(String name, int ind) throws SocketException;
- private native static boolean isLoopback0(String name, int ind) throws SocketException;
- private native static boolean supportsMulticast0(String name, int ind) throws SocketException;
- private native static boolean isP2P0(String name, int ind) throws SocketException;
- private native static int getMTU0(String name, int ind) throws SocketException;
+ private int getFlags() throws SocketException {
+ FileDescriptor fd = null;
+ try {
+ fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, 0);
+ return Libcore.os.ioctlFlags(fd, name);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsSocketException();
+ } catch (Exception ex) {
+ throw new SocketException(ex);
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ }
/**
* Compares this object against the specified object.
diff --git a/ojluni/src/main/java/java/util/Observable.java b/ojluni/src/main/java/java/util/Observable.java
index 48c6c13..1d8be3b 100755
--- a/ojluni/src/main/java/java/util/Observable.java
+++ b/ojluni/src/main/java/java/util/Observable.java
@@ -138,18 +138,19 @@
synchronized (this) {
/* We don't want the Observer doing callbacks into
- * arbitrary code while holding its own Monitor.
+ * arbitrary Observables while holding its own Monitor.
* The code where we extract each Observable from
- * the Vector and store the state of the Observer
+ * the ArrayList and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
+ *
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
- if (!changed)
+ if (!hasChanged())
return;
arrLocal = observers.toArray(new Observer[observers.size()]);
diff --git a/ojluni/src/main/native/NetworkInterface.c b/ojluni/src/main/native/NetworkInterface.c
index 48450e1..ad89692 100755
--- a/ojluni/src/main/native/NetworkInterface.c
+++ b/ojluni/src/main/native/NetworkInterface.c
@@ -108,7 +108,6 @@
/** Private methods declarations **/
static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
-static int getFlags0(JNIEnv *env, jstring ifname);
static netif *enumInterfaces(JNIEnv *env);
@@ -116,12 +115,10 @@
static void freeif(netif *ifs);
static int openSocket(JNIEnv *env, int proto);
-static int openSocketWithFallback(JNIEnv *env, const char *ifname);
static int getIndex(int sock, const char *ifname);
static int getFlags(int sock, const char *ifname, int *flags);
-static int getMTU(JNIEnv *env, int sock, const char *ifname);
/******************* Java entry points *****************************/
@@ -382,109 +379,8 @@
return netIFArr;
}
-
-/*
- * Class: java_net_NetworkInterface
- * Method: isUp0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) {
- int ret = getFlags0(env, name);
- return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE : JNI_FALSE;
-}
-
-/*
- * Class: java_net_NetworkInterface
- * Method: isP2P0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
- int ret = getFlags0(env, name);
- return (ret & IFF_POINTOPOINT) ? JNI_TRUE : JNI_FALSE;
-}
-
-/*
- * Class: java_net_NetworkInterface
- * Method: isLoopback0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) {
- int ret = getFlags0(env, name);
- return (ret & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE;
-}
-
-/*
- * Class: java_net_NetworkInterface
- * Method: supportsMulticast0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) {
- int ret = getFlags0(env, name);
- return (ret & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE;
-}
-
-/*
- * Class: java_net_NetworkInterface
- * Method: getMTU0
- * Signature: ([bLjava/lang/String;I)I
- */
-
-JNIEXPORT jint JNICALL NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
- jboolean isCopy;
- int ret = -1;
- int sock;
- const char* name_utf;
-
- name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
-
- if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
- (*env)->ReleaseStringUTFChars(env, name, name_utf);
- return JNI_FALSE;
- }
-
- ret = getMTU(env, sock, name_utf);
-
- (*env)->ReleaseStringUTFChars(env, name, name_utf);
-
- untagSocket(env, sock);
- close(sock);
- return ret;
-}
-
/*** Private methods definitions ****/
-static int getFlags0(JNIEnv *env, jstring name) {
- jboolean isCopy;
- int ret, sock;
- const char* name_utf;
- int flags = 0;
-
- name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
-
- if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
- (*env)->ReleaseStringUTFChars(env, name, name_utf);
- return -1;
- }
-
- name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
-
- ret = getFlags(sock, name_utf, &flags);
-
- untagSocket(env, sock);
- close(sock);
- (*env)->ReleaseStringUTFChars(env, name, name_utf);
-
- if (ret < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFFLAGS failed");
- return -1;
- }
-
- return flags;
-}
-
-
-
-
/*
* Create a NetworkInterface object, populate the name and index, and
* populate the InetAddress array based on the IP addresses for this
@@ -989,34 +885,6 @@
/** Linux **/
-/* Open socket for further ioct calls, try v4 socket first and
- * if it falls return v6 socket
- */
-
-static int openSocketWithFallback(JNIEnv *env, const char *ifname){
- int sock;
- struct ifreq if2;
-
- if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- if (errno == EPROTONOSUPPORT){
- if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
- NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
- return -1;
- }
- }
- else{ // errno is not NOSUPPORT
- NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
- return -1;
- }
- }
-
- /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
- of address of an interface */
-
- tagSocket(env, sock);
- return sock;
-}
-
static int getIndex(int sock, const char *name){
/*
* Try to get the interface index
@@ -1032,19 +900,6 @@
return if2.ifr_ifindex;
}
-static int getMTU(JNIEnv *env, int sock, const char *ifname) {
- struct ifreq if2;
-
- memset((char *) &if2, 0, sizeof(if2));
- strcpy(if2.ifr_name, ifname);
-
- if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
- return -1;
- }
-
- return if2.ifr_mtu;
-}
static int getFlags(int sock, const char *ifname, int *flags) {
struct ifreq if2;
@@ -1065,11 +920,6 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(NetworkInterface, getMTU0, "(Ljava/lang/String;I)I"),
- NATIVE_METHOD(NetworkInterface, supportsMulticast0, "(Ljava/lang/String;I)Z"),
- NATIVE_METHOD(NetworkInterface, isLoopback0, "(Ljava/lang/String;I)Z"),
- NATIVE_METHOD(NetworkInterface, isP2P0, "(Ljava/lang/String;I)Z"),
- NATIVE_METHOD(NetworkInterface, isUp0, "(Ljava/lang/String;I)Z"),
NATIVE_METHOD(NetworkInterface, getAll, "()[Ljava/net/NetworkInterface;"),
NATIVE_METHOD(NetworkInterface, getByInetAddress0, "(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;"),
NATIVE_METHOD(NetworkInterface, getByIndex0, "(I)Ljava/net/NetworkInterface;"),
diff --git a/ojluni/src/main/native/java_net_NetworkInterface.h b/ojluni/src/main/native/java_net_NetworkInterface.h
index 05472e8..53391d3 100644
--- a/ojluni/src/main/native/java_net_NetworkInterface.h
+++ b/ojluni/src/main/native/java_net_NetworkInterface.h
@@ -68,38 +68,6 @@
/*
* Class: java_net_NetworkInterface
- * Method: isUp0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_isUp0
- (JNIEnv *, jclass, jstring, jint);
-
-/*
- * Class: java_net_NetworkInterface
- * Method: isLoopback0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_isLoopback0
- (JNIEnv *, jclass, jstring, jint);
-
-/*
- * Class: java_net_NetworkInterface
- * Method: supportsMulticast0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_supportsMulticast0
- (JNIEnv *, jclass, jstring, jint);
-
-/*
- * Class: java_net_NetworkInterface
- * Method: isP2P0
- * Signature: (Ljava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL NetworkInterface_isP2P0
- (JNIEnv *, jclass, jstring, jint);
-
-/*
- * Class: java_net_NetworkInterface
* Method: getMacAddr0
* Signature: ([BLjava/lang/String;I)[B
*/
@@ -108,14 +76,6 @@
/*
* Class: java_net_NetworkInterface
- * Method: getMTU0
- * Signature: (Ljava/lang/String;I)I
- */
-JNIEXPORT jint JNICALL NetworkInterface_getMTU0
- (JNIEnv *, jclass, jstring, jint);
-
-/*
- * Class: java_net_NetworkInterface
* Method: init
* Signature: ()V
*/