diff options
author | Sho Amano <samano@xevo.com> | 2018-10-02 18:57:42 +0900 |
---|---|---|
committer | Sho Amano <samano@xevo.com> | 2018-10-10 14:49:51 +0900 |
commit | f4a8bd5078ce777433ec125bc44e7d9773989ff2 (patch) | |
tree | c333b0fb5e7ab4f29103880bf939e99bdcb868a7 | |
parent | f099f7c6431dd661bd314396722154c57d1499c0 (diff) | |
download | sdl_android-f4a8bd5078ce777433ec125bc44e7d9773989ff2.tar.gz |
fix: MultiplexTcpTransport may open socket via mobile network
On Android 5+, a Socket will be bound to mobile network if
the phone is connected to a Wi-Fi network with no Internet
connectivity. This "feature" prevents us from making a local
TCP connection between Core.
This fix makes sure that the TCP transport works with head
units that provide no Internet connectivity over their Wi-Fi.
3 files changed, 63 insertions, 3 deletions
diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java index 71dd8f6ee..d5843f4c2 100644 --- a/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java +++ b/sdl_android/src/main/java/com/smartdevicelink/transport/MultiplexTcpTransport.java @@ -32,6 +32,7 @@ package com.smartdevicelink.transport; +import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -39,6 +40,7 @@ import android.util.Log; import com.smartdevicelink.protocol.SdlPacket; import com.smartdevicelink.transport.enums.TransportType; +import com.smartdevicelink.transport.utl.WiFiSocketFactory; import java.io.IOException; import java.io.InputStream; @@ -65,14 +67,16 @@ public class MultiplexTcpTransport extends MultiplexBaseTransport { private OutputStream mOutputStream = null; private MultiplexTcpTransport.TcpTransportThread mThread = null; private WriterThread writerThread; + private Context mContext; - public MultiplexTcpTransport(int port, String ipAddress, boolean autoReconnect, Handler handler) { + public MultiplexTcpTransport(int port, String ipAddress, boolean autoReconnect, Handler handler, Context context) { super(handler, TransportType.TCP); this.ipAddress = ipAddress; this.port = port; connectedDeviceAddress = ipAddress + ":" + port; this.autoReconnect = autoReconnect; + mContext = context; setState(STATE_NONE); } @@ -214,7 +218,7 @@ public class MultiplexTcpTransport extends MultiplexBaseTransport { } logInfo(String.format("TCPTransport.connect: Socket is closed. Trying to connect to %s", getAddress())); - mSocket = new Socket(); + mSocket = WiFiSocketFactory.createSocket(mContext); mSocket.connect(new InetSocketAddress(ipAddress, port)); mOutputStream = mSocket.getOutputStream(); mInputStream = mSocket.getInputStream(); diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java index ec61a13e3..50c5b5412 100644 --- a/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java +++ b/sdl_android/src/main/java/com/smartdevicelink/transport/SdlRouterService.java @@ -650,7 +650,7 @@ public class SdlRouterService extends Service{ }//else { TCP transport does not exists.} //TCP transport either doesn't exist or is not connected. Start one up. - service.tcpTransport = new MultiplexTcpTransport(port, ipAddress, true, service.tcpHandler); + service.tcpTransport = new MultiplexTcpTransport(port, ipAddress, true, service.tcpHandler, service); service.tcpTransport.start(); } diff --git a/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java new file mode 100644 index 000000000..ae17fc5a9 --- /dev/null +++ b/sdl_android/src/main/java/com/smartdevicelink/transport/utl/WiFiSocketFactory.java @@ -0,0 +1,56 @@ +package com.smartdevicelink.transport.utl; + +import android.annotation.TargetApi; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.os.Build; + +import java.io.IOException; +import java.net.Socket; + +import javax.net.SocketFactory; + +import static com.smartdevicelink.util.NativeLogTool.logInfo; + +public class WiFiSocketFactory { + /** + * Creates a TCP socket which is bound to Wi-Fi network (for Android 5+) + * + * On Android 5 and later, this method returns a Socket which is always bound to a Wi-Fi + * network. If the phone is not connected to a Wi-Fi network, this method throws an IOException. + * Prior to Android 5, this method simply creates a Socket equivalent to "new Socket();". + * + * @return a Socket instance bound to Wi-Fi network. + */ + public static Socket createSocket(Context context) throws IOException { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + SocketFactory factory = retrieveSocketFactory(context); + if (factory == null) { + logInfo("Cannot find Wi-Fi network, aborting socket creation."); + throw new IOException("The phone is not connected to Wi-Fi network"); + } + return factory.createSocket(); + } else { + return new Socket(); + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private static SocketFactory retrieveSocketFactory(Context context) { + ConnectivityManager connMan = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + // requires ACCESS_NETWORK_STATE permission + Network[] allNetworks = connMan.getAllNetworks(); + + for (Network network : allNetworks) { + // requires ACCESS_NETWORK_STATE permission + NetworkCapabilities capabilities = connMan.getNetworkCapabilities(network); + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + return network.getSocketFactory(); + } + } + + return null; + } +} |