netty: Infinite Selector rebuild loop of death.

I’m experiencing an issue that has been reported about before. None of the reports are giving me any hints though. (e.g. #2426 and #2616)

The problem: I’m starting a Websocket server with ServerBootstrap bound to the wifi IP address on Android. As soon the wifi connection changes or wifi is disabled completely, the log will be flooded with the following two messages, repeated about 100 times per second while the app is not usable anymore.

W/NioEventLoop: Selector.select() returned prematurely 512 times in a row; rebuilding Selector sun.nio.ch.PollSelectorImpl@e54f195.
I/NioEventLoop: Migrated 1 channel(s) to the new Selector.

Steps to reproduce

Run the below code on an android device and while the app is running switch off wifi or change to another wifi hotspot.

Minimal yet complete reproducer code (or URL to code)

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.google.common.net.InetAddresses;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteOrder;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;

public class MainActivity extends AppCompatActivity {
    private EventLoopGroup group;
    protected InetSocketAddress localAddress;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        localAddress = new InetSocketAddress(getLocalIPAddress(this), 0);
        group = new NioEventLoopGroup();
        ServerBootstrap tcp = new ServerBootstrap();

        tcp.group(group)
            .channel(NioServerSocketChannel.class)
            .childHandler(new ChannelInitializer() {
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    addLast("server",
                            ch.pipeline(),
                            new HttpServerCodec()
                    );
                }
            });

        tcp.bind(localAddress);

        ChannelFuture future = tcp.bind(localAddress);
        try {
            future.sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void addLast(String prefix, ChannelPipeline pipeline, ChannelHandler... channelHandlers) {
        for (ChannelHandler handler : channelHandlers) {
            String name = (prefix + handler.getClass().getSimpleName()).intern();
            pipeline.addLast(name, handler);
        }
    }

    protected EventLoopGroup newEventLoopGroup(int maxChannels) {
        return new NioEventLoopGroup(maxChannels);
    }

    protected final EventLoopGroup newEventLoopGroup() {
        return newEventLoopGroup(0);
    }

    public static InetAddress getLocalIPAddress(Context context) {
        WifiManager wifiManager = (WifiManager) context.getSystemService(WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        int ip = wifiInfo.getIpAddress();
        if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
            ip = Integer.reverseBytes(ip);
        }
        return InetAddresses.fromInteger(ip);
    }
}
dependencies {
    ...
    implementation 'io.netty:netty-codec-http:4.1.22.Final'
    implementation 'io.netty:netty-handler:4.1.22.Final'
    implementation 'com.google.guava:guava:20.0'
    ...
}

Netty version

4.1.22.Final

JVM version (e.g. java -version)

7

OS version (e.g. uname -a)

Android 7.0

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 33 (21 by maintainers)

Most upvoted comments

This is reproducible on Android 8 for me as well. selector.select() returns immediately with OP_ACCEPT on the selected key set, then invoking accept() triggers an “Invalid argument” IOException from native code, and this just repeats indefinitely. I’m following up with some Android system folks about this, will update here if I get any additional information.