1

I'm developing a multiplayer game with libGDX and my problem is that the code that works on desktop. It causes a crash on android. When I start the server's thread on android, the following error occurs:

FATAL EXCEPTION: YellowServer
com.badlogic.gdx.utils.GdxRuntimeException: Cannot create a server socket at port 4444.
at com.badlogic.gdx.net.NetJavaServerSocketImpl.<init>(NetJavaServerSocketImpl.java:63)
at com.badlogic.gdx.backends.android.AndroidNet.newServerSocket(AndroidNet.java:60)
at hu.hundevelopers.yellow.net.NetServer.<init>(NetServer.java:41)
at hu.hundevelopers.yellow.YellowServer.create(YellowServer.java:32)
at hu.hundevelopers.yellow.YellowServer.run(YellowServer.java:61)
Caused by: java.net.SocketException: socket failed: EACCES (Permission denied)
at libcore.io.IoBridge.socket(IoBridge.java:583)
at java.net.PlainSocketImpl.create(PlainSocketImpl.java:201)
at java.net.PlainServerSocketImpl.create(PlainServerSocketImpl.java:38)
at java.net.ServerSocket.<init>(ServerSocket.java:59)
at com.badlogic.gdx.net.NetJavaServerSocketImpl.<init>(NetJavaServerSocketImpl.java:46)
... 4 more
Caused by: libcore.io.ErrnoException: socket failed: EACCES (Permission denied)
at libcore.io.Posix.socket(Native Method)
at libcore.io.BlockGuardOs.socket(BlockGuardOs.java:181)
at libcore.io.IoBridge.socket(IoBridge.java:568)
... 8 more

It looks like that I forgot the permissions from the manifest xml file but they're there:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

NetServer.java:

package hu.hundevelopers.yellow.net;

import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.net.ServerSocket;

import hu.hundevelopers.yellow.YellowServer;
import hu.hundevelopers.yellow.net.packet.Packet;

public class NetServer {
    public class ListenThread extends Thread {
        public NetServer net;

        public ListenThread(NetServer net) {
            super("ListenThread");
            this.net = net;
        }

        @Override
        public void run() {
            try {
                while (this.net.server.game.isHosting) {
                    NetServerClient client = new NetServerClient(this.net, this.net.socket.accept(this.net.server.game.socketHints));
                    this.net.clients.add(client);
                }
            } catch (Exception e) {

            }
        }
    }

    public YellowServer server;
    public ServerSocket socket;
    public List<NetServerClient> clients;

    public NetServer(YellowServer server, int port) {
        this.server = server;
        this.socket = Gdx.net.newServerSocket(Net.Protocol.TCP, port, this.server.game.serverSocketHints);
        this.clients = new ArrayList<NetServerClient>();
        new ListenThread(this).start();
    }

    public void sendToAll(Packet pkt) {
        for (NetServerClient client : this.clients)
            client.send(pkt);
    }

    public void sendToAllAndDispose(Packet pkt) {
        this.sendToAll(pkt);
        pkt.dispose();
    }

    public void update() {
        for (int i = 0; i < this.clients.size(); i++) {
            this.clients.get(i).update();
            if (!this.clients.get(i).connection) {
                this.clients.get(i).dispose();
                this.clients.remove(i--);
            }
        }
    }

    public void dispose() {
        for(NetServerClient client : this.clients)
            client.dispose();
        this.socket.dispose();
    }
}

Edit:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="hu.hundevelopers.yellow.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/GdxTheme" >
        <activity
            android:name="hu.hundevelopers.yellow.android.AndroidLauncher"
            android:label="@string/app_name" 
            android:screenOrientation="landscape"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

AndroidLauncher.java:

package hu.hundevelopers.yellow.android;

import android.content.pm.PackageManager;
import android.os.Bundle;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;

import hu.hundevelopers.yellow.Yellow;

public class AndroidLauncher extends AndroidApplication {
    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
        initialize(new Yellow(new String[]{}), config);
        if(getContext().checkCallingOrSelfPermission("android.permission.INTERNET") == PackageManager.PERMISSION_GRANTED) {
            Gdx.app.log("INFO", "PERMISSION GRANTED");
        } else {
            Gdx.app.log("ERROR", "PERMISSION DENIED");
        }
    }
}
FBalazs
  • 23
  • 5

2 Answers2

1

I solved the problem. I changed the minimum required android version from 8 to 10 and now everything works.

FBalazs
  • 23
  • 5
0

The exception indicates its a permission problem. So, there may be something going amiss in your packaging or deployment steps (or the manifest isn't doing what you intend).

You can add a bit of debugging code to verify that you do not have the permission. See How permission can be checked at runtime without throwing SecurityException? That should help narrow the problem down.

Community
  • 1
  • 1
P.T.
  • 24,557
  • 7
  • 64
  • 95
  • With libGDX the game is a seperate project from the android application so I couldn't test the permission where I open the socket but I tested in the onCreate method of the application. The result was surprising: the app doesn't have the permission. I'm adding the Activity and the manifest file to the question right now. – FBalazs Aug 08 '14 at 18:18