diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml
index 56d6eadfbf..dab8ce63a3 100644
--- a/Source/Android/app/src/main/AndroidManifest.xml
+++ b/Source/Android/app/src/main/AndroidManifest.xml
@@ -19,6 +19,7 @@
+
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java
new file mode 100644
index 0000000000..08e9c9731f
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java
@@ -0,0 +1,126 @@
+package org.dolphinemu.dolphinemu.utils;
+
+import android.app.Service;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.RouteInfo;
+import android.os.Build;
+
+import androidx.annotation.Keep;
+import androidx.annotation.RequiresApi;
+
+import org.dolphinemu.dolphinemu.DolphinApplication;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+
+public class NetworkHelper
+{
+ private static ConnectivityManager GetConnectivityManager()
+ {
+ Context context = DolphinApplication.getAppContext();
+ ConnectivityManager manager =
+ (ConnectivityManager) context.getSystemService(Service.CONNECTIVITY_SERVICE);
+ if (manager == null)
+ Log.warning("Cannot get Network link as ConnectivityManager is null.");
+ return manager;
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.M)
+ private static LinkAddress GetIPv4Link()
+ {
+ ConnectivityManager manager = GetConnectivityManager();
+ if (manager == null)
+ return null;
+ Network active_network = manager.getActiveNetwork();
+ if (active_network == null)
+ {
+ Log.warning("Active network is null.");
+ return null;
+ }
+ LinkProperties properties = manager.getLinkProperties(active_network);
+ if (properties == null)
+ {
+ Log.warning("Link properties is null.");
+ return null;
+ }
+ for (LinkAddress link : properties.getLinkAddresses())
+ {
+ InetAddress address = link.getAddress();
+ if (address instanceof Inet4Address)
+ return link;
+ }
+ Log.warning("No IPv4 link found.");
+ return null;
+ }
+
+ private static int InetAddressToInt(InetAddress address)
+ {
+ byte[] net_addr = address.getAddress();
+ int result = 0;
+ // Convert address to little endian
+ for (int i = 0; i < net_addr.length; i++)
+ {
+ result |= (net_addr[i] & 0xFF) << (8 * i);
+ }
+ return result;
+ }
+
+ @Keep
+ public static int GetNetworkIpAddress()
+ {
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M)
+ return 0;
+ LinkAddress link = GetIPv4Link();
+ if (link == null)
+ return 0;
+ return InetAddressToInt(link.getAddress());
+ }
+
+ @Keep
+ public static int GetNetworkPrefixLength()
+ {
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M)
+ return 0;
+ LinkAddress link = GetIPv4Link();
+ if (link == null)
+ return 0;
+ return link.getPrefixLength();
+ }
+
+ @Keep
+ public static int GetNetworkGateway()
+ {
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M)
+ return 0;
+ ConnectivityManager manager = GetConnectivityManager();
+ if (manager == null)
+ return 0;
+ Network active_network = manager.getActiveNetwork();
+ if (active_network == null)
+ return 0;
+ LinkProperties properties = manager.getLinkProperties(active_network);
+ if (properties == null)
+ return 0;
+ try
+ {
+ InetAddress addr_out = InetAddress.getByName("8.8.8.8");
+ for (RouteInfo route : properties.getRoutes())
+ {
+ if (!route.matches(addr_out))
+ continue;
+ return InetAddressToInt(route.getGateway());
+ }
+ }
+ catch (UnknownHostException ignore)
+ {
+ }
+ Log.warning("No valid gateway found.");
+ return 0;
+ }
+}
diff --git a/Source/Android/jni/AndroidCommon/AndroidCommon.cpp b/Source/Android/jni/AndroidCommon/AndroidCommon.cpp
index 73405b6d8e..887ae4deab 100644
--- a/Source/Android/jni/AndroidCommon/AndroidCommon.cpp
+++ b/Source/Android/jni/AndroidCommon/AndroidCommon.cpp
@@ -65,3 +65,24 @@ bool DeleteAndroidContent(const std::string& uri)
return env->CallStaticBooleanMethod(IDCache::GetContentHandlerClass(),
IDCache::GetContentHandlerDelete(), ToJString(env, uri));
}
+
+int GetNetworkIpAddress()
+{
+ JNIEnv* env = IDCache::GetEnvForThread();
+ return env->CallStaticIntMethod(IDCache::GetNetworkHelperClass(),
+ IDCache::GetNetworkHelperGetNetworkIpAddress());
+}
+
+int GetNetworkPrefixLength()
+{
+ JNIEnv* env = IDCache::GetEnvForThread();
+ return env->CallStaticIntMethod(IDCache::GetNetworkHelperClass(),
+ IDCache::GetNetworkHelperGetNetworkPrefixLength());
+}
+
+int GetNetworkGateway()
+{
+ JNIEnv* env = IDCache::GetEnvForThread();
+ return env->CallStaticIntMethod(IDCache::GetNetworkHelperClass(),
+ IDCache::GetNetworkHelperGetNetworkGateway());
+}
diff --git a/Source/Android/jni/AndroidCommon/AndroidCommon.h b/Source/Android/jni/AndroidCommon/AndroidCommon.h
index ca8245182d..2ab220eac7 100644
--- a/Source/Android/jni/AndroidCommon/AndroidCommon.h
+++ b/Source/Android/jni/AndroidCommon/AndroidCommon.h
@@ -14,3 +14,6 @@ std::vector JStringArrayToVector(JNIEnv* env, jobjectArray array);
int OpenAndroidContent(const std::string& uri, const std::string& mode);
bool DeleteAndroidContent(const std::string& uri);
+int GetNetworkIpAddress();
+int GetNetworkPrefixLength();
+int GetNetworkGateway();
diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp
index fcfd4ed177..674233d79f 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.cpp
+++ b/Source/Android/jni/AndroidCommon/IDCache.cpp
@@ -45,6 +45,11 @@ static jclass s_content_handler_class;
static jmethodID s_content_handler_open_fd;
static jmethodID s_content_handler_delete;
+static jclass s_network_helper_class;
+static jmethodID s_network_helper_get_network_ip_address;
+static jmethodID s_network_helper_get_network_prefix_length;
+static jmethodID s_network_helper_get_network_gateway;
+
namespace IDCache
{
JNIEnv* GetEnvForThread()
@@ -205,6 +210,25 @@ jmethodID GetContentHandlerDelete()
return s_content_handler_delete;
}
+jclass GetNetworkHelperClass()
+{
+ return s_network_helper_class;
+}
+
+jmethodID GetNetworkHelperGetNetworkIpAddress()
+{
+ return s_network_helper_get_network_ip_address;
+}
+
+jmethodID GetNetworkHelperGetNetworkPrefixLength()
+{
+ return s_network_helper_get_network_prefix_length;
+}
+
+jmethodID GetNetworkHelperGetNetworkGateway()
+{
+ return s_network_helper_get_network_gateway;
+}
} // namespace IDCache
#ifdef __cplusplus
@@ -283,6 +307,16 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
s_content_handler_delete =
env->GetStaticMethodID(s_content_handler_class, "delete", "(Ljava/lang/String;)Z");
+ const jclass network_helper_class =
+ env->FindClass("org/dolphinemu/dolphinemu/utils/NetworkHelper");
+ s_network_helper_class = reinterpret_cast(env->NewGlobalRef(network_helper_class));
+ s_network_helper_get_network_ip_address =
+ env->GetStaticMethodID(s_network_helper_class, "GetNetworkIpAddress", "()I");
+ s_network_helper_get_network_prefix_length =
+ env->GetStaticMethodID(s_network_helper_class, "GetNetworkPrefixLength", "()I");
+ s_network_helper_get_network_gateway =
+ env->GetStaticMethodID(s_network_helper_class, "GetNetworkGateway", "()I");
+
return JNI_VERSION;
}
@@ -301,6 +335,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved)
env->DeleteGlobalRef(s_ini_file_section_class);
env->DeleteGlobalRef(s_compress_cb_class);
env->DeleteGlobalRef(s_content_handler_class);
+ env->DeleteGlobalRef(s_network_helper_class);
}
#ifdef __cplusplus
diff --git a/Source/Android/jni/AndroidCommon/IDCache.h b/Source/Android/jni/AndroidCommon/IDCache.h
index cd45b5d03f..c89e0c9fcc 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.h
+++ b/Source/Android/jni/AndroidCommon/IDCache.h
@@ -45,4 +45,9 @@ jclass GetContentHandlerClass();
jmethodID GetContentHandlerOpenFd();
jmethodID GetContentHandlerDelete();
+jclass GetNetworkHelperClass();
+jmethodID GetNetworkHelperGetNetworkIpAddress();
+jmethodID GetNetworkHelperGetNetworkPrefixLength();
+jmethodID GetNetworkHelperGetNetworkGateway();
+
} // namespace IDCache
diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp
index 24262d7b9b..68fadeadf5 100644
--- a/Source/Core/Core/IOS/Network/IP/Top.cpp
+++ b/Source/Core/Core/IOS/Network/IP/Top.cpp
@@ -50,6 +50,10 @@
#include
#endif
+#ifdef __ANDROID__
+#include "jni/AndroidCommon/AndroidCommon.h"
+#endif
+
namespace IOS::HLE::Device
{
enum SOResultCode : s32
@@ -217,7 +221,14 @@ static std::optional GetSystemDefaultInterface()
return DefaultInterface{entry.dwAddr, entry.dwMask, entry.dwBCastAddr};
}
}
-#elif !defined(__ANDROID__)
+#elif defined(__ANDROID__)
+ const u32 addr = GetNetworkIpAddress();
+ const u32 prefix_length = GetNetworkPrefixLength();
+ const u32 netmask = (1 << prefix_length) - 1;
+ const u32 gateway = GetNetworkGateway();
+ if (addr || netmask || gateway)
+ return DefaultInterface{addr, netmask, gateway};
+#else
// Assume that the address that is used to access the Internet corresponds
// to the default interface.
auto get_default_address = []() -> std::optional {
@@ -261,7 +272,7 @@ static std::optional GetSystemDefaultInterface()
}
}
#endif
- return {};
+ return std::nullopt;
}
static DefaultInterface GetSystemDefaultInterfaceOrFallback()