16b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson/*
26b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * Copyright (C) 2010 The Android Open Source Project
36b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson *
46b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
56b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * you may not use this file except in compliance with the License.
66b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * You may obtain a copy of the License at
76b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson *
86b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
96b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson *
106b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * Unless required by applicable law or agreed to in writing, software
116b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
126b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * See the License for the specific language governing permissions and
146b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * limitations under the License.
156b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson */
164557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.java.nio.channels;
176b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson
18173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamathimport android.system.Os;
196b739231f8985f33f20672fe727fde0d0f023eadJesse Wilsonimport java.io.IOException;
20d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.net.InetSocketAddress;
21d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.net.ServerSocket;
22173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamathimport java.io.FileDescriptor;
2357656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughesimport java.nio.ByteBuffer;
24d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.NoConnectionPendingException;
25d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.SelectionKey;
264557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.nio.channels.Selector;
27d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.ServerSocketChannel;
28d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.SocketChannel;
29d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.util.concurrent.CountDownLatch;
30d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.util.concurrent.TimeUnit;
316b739231f8985f33f20672fe727fde0d0f023eadJesse Wilsonimport junit.framework.TestCase;
326b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson
336b739231f8985f33f20672fe727fde0d0f023eadJesse Wilsonpublic class SelectorTest extends TestCase {
34d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes    public void testNonBlockingConnect_immediate() throws Exception {
35d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        // Test the case where we [probably] connect immediately.
36d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        Selector selector = Selector.open();
37d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        ServerSocketChannel ssc = ServerSocketChannel.open();
38d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        try {
39d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            ssc.configureBlocking(false);
40d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            ssc.socket().bind(null);
41d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes
42d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            SocketChannel sc = SocketChannel.open();
43d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            sc.configureBlocking(false);
44d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            sc.connect(ssc.socket().getLocalSocketAddress());
45d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);
46d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            assertEquals(1, selector.select());
47d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
48d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            sc.finishConnect();
49d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        } finally {
50d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            selector.close();
51d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            ssc.close();
52d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        }
53d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes    }
54d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes
55d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes    // http://code.google.com/p/android/issues/detail?id=15388
56d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes    public void testInterrupted() throws IOException {
57d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        Selector selector = Selector.open();
580bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller        Thread.currentThread().interrupt();
59d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        try {
60d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            int count = selector.select();
61d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            assertEquals(0, count);
62e37bfbcea35237c5c61f4d94788eafbc5f1f4ee8Neil Fuller            assertTrue(Thread.currentThread().isInterrupted());
63d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        } finally {
640bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller            // Clear the interrupted thread state so that it does not interfere with later tests.
650bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller            Thread.interrupted();
660bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller
67d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            selector.close();
68d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        }
69d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes    }
70d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes
71d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes    public void testManyWakeupCallsTriggerOnlyOneWakeup() throws Exception {
72d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        final Selector selector = Selector.open();
73d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        try {
74d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            selector.wakeup();
75d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            selector.wakeup();
76d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            selector.wakeup();
77d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            selector.select();
78d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes
79d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            // create a latch that will reach 0 when select returns
80d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            final CountDownLatch selectReturned = new CountDownLatch(1);
81d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            Thread thread = new Thread(new Runnable() {
82d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes                @Override public void run() {
83d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes                    try {
84d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes                        selector.select();
85d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes                        selectReturned.countDown();
86d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes                    } catch (IOException ignored) {
87d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes                    }
88d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes                }
89d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            });
90d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            thread.start();
91d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes
92d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            // select doesn't ever return, so await() times out and returns false
938b3d7dfa1b50eb611b20824242f35eba2cfba46eElliott Hughes            assertFalse(selectReturned.await(2, TimeUnit.SECONDS));
94d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        } finally {
95d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes            selector.close();
96d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes        }
97d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes    }
986b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson
9957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes    // We previously leaked a file descriptor for each selector instance created.
10057656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes    //
10157656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=5993
10257656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=4825
1036b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    public void testLeakingPipes() throws IOException {
1046b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        for (int i = 0; i < 2000; i++) {
1056b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson            Selector selector = Selector.open();
1066b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson            selector.close();
1076b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        }
1086b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    }
10957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes
11057656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes    public void test_57456() throws Exception {
11199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        Selector selector = Selector.open();
11299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        ServerSocketChannel ssc = ServerSocketChannel.open();
11399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller
11499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        try {
11599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            // Connect.
11699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            ssc.configureBlocking(false);
11799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            ssc.socket().bind(null);
11899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            SocketChannel sc = SocketChannel.open();
11999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            sc.connect(ssc.socket().getLocalSocketAddress());
12099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            sc.finishConnect();
12199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller
12299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            // Switch to non-blocking so we can use a Selector.
12399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            sc.configureBlocking(false);
12499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller
12599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            // Have the 'server' write something.
12699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            ssc.accept().write(ByteBuffer.allocate(128));
12799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller
12899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            // At this point, the client should be able to read or write immediately.
12999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            // (It shouldn't be able to connect because it's already connected.)
13099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            SelectionKey key = sc.register(selector,
13199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller                    SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
13299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            assertEquals(1, selector.select());
13399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, key.readyOps());
13499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            assertEquals(0, selector.select());
13599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        } finally {
13699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            selector.close();
13799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            ssc.close();
13899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        }
13999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller    }
14099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller
14199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller    // http://code.google.com/p/android/issues/detail?id=80785
14299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller    public void test_80785() throws Exception {
14399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        Selector selector = Selector.open();
14457656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes        selector.close();
14599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller
14699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        // Historically on android this did not throw an exception. Due to the bug it would throw
14799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        // an (undeclared) IOException.
14899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        selector.wakeup();
14957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes    }
150173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
151173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath    public void test28318596() throws Exception {
152173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath        Selector selector = Selector.open();
153173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath        ServerSocketChannel ssc = ServerSocketChannel.open();
154173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath        SocketChannel server = null;
155173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath        FileDescriptor dup = null;
156173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath        try {
157173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            ssc.configureBlocking(false);
158173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            ssc.bind(null);
159173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            SocketChannel sc = SocketChannel.open();
160173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            sc.connect(ssc.getLocalAddress());
161173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            sc.finishConnect();
162173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
163173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // Switch to non-blocking so we can use a Selector.
164173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            sc.configureBlocking(false);
165173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
166173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
167173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            assertEquals(1, selector.select(100));
168173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            assertEquals(0, selector.select(100));
169173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
170173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            server = ssc.accept();
171173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            server.write(ByteBuffer.allocate(8192));
172173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
173173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // This triggered b/28318596. We'd call through to preClose() which would dup2
174173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // a known sink descriptor into the channel's descriptor. All subsequent calls
175173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // to epoll_ctl(EPOLL_CTL_DEL) would then fail because the kernel was unhappy about
176173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // the fact that the descriptor was associated with a different file. This meant that
177173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // we'd spuriously return from select because we've never managed to remove the file
178173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // associated with the selection key from the epoll fd's interest set.
179173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            server.shutdownInput();
180173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            server.shutdownOutput();
181173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // We dup the socket here to work around kernel cleanup mechanisms. The kernel will
182173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // automatically unregister a file reference from all associated epoll instances once
183173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // the last non-epoll instance has been closed.
184173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            dup = Os.dup(sc.socket().getFileDescriptor$());
185173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            sc.close();
186173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
187173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // The following is a finicky loop to try and figure out whether we're going into
188173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // a tight loop where select returns immediately (we should've received a POLLHUP
189173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // and/or POLLIN on |sc|).
190173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            long start = System.currentTimeMillis();
191173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            for (int i = 0; i < 10; ++i) {
192173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath                assertEquals(0, selector.select(500));
193173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            }
194173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
195173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            server.close();
196173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            long end = System.currentTimeMillis();
197173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // There should have been no events during the loop above (the size of
198173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // the interest set is zero) so all of the selects should timeout and take
199173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            // ~5000ms.
200173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            assertTrue("Time taken: " + (end - start), (end - start) > 2000);
201173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath        } finally {
202173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            selector.close();
203173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            ssc.close();
204173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
205173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            if (server != null) {
206173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath                server.close();
207173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            }
208173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath
209173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            if (dup != null) {
210173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath                Os.close(dup);
211173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath            }
212173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath        }
213173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath    }
2146b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson}
215