diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml
index 56d6eadfbf69..4975056c57f6 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 000000000000..b7c245c1036b
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/NetworkHelper.java
@@ -0,0 +1,109 @@
+package org.dolphinemu.dolphinemu.utils;
+
+import android.app.Service;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import android.os.Build;
+
+import androidx.annotation.RequiresApi;
+
+import org.dolphinemu.dolphinemu.NativeLibrary;
+
+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 = NativeLibrary.getEmulationActivity();
+ if (context == null)
+ {
+ Log.warning("Cannot get Network IP address as EmulationActivity is null.");
+ return null;
+ }
+ 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;
+ List links =
+ manager.getLinkProperties(manager.getActiveNetwork()).getLinkAddresses();
+ for (LinkAddress link : links)
+ {
+ 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;
+ }
+
+ 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());
+ }
+
+ 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();
+ }
+
+ 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;
+ List routes = manager.getLinkProperties(manager.getActiveNetwork()).getRoutes();
+ try
+ {
+ InetAddress addr_out = InetAddress.getByName("8.8.8.8");
+ for (RouteInfo route : routes)
+ {
+ if (!route.matches(addr_out))
+ continue;
+ return InetAddressToInt(route.getGateway());
+ }
+ }
+ catch (UnknownHostException ignore)
+ {
+ }
+ return 0;
+ }
+}
diff --git a/Source/Android/jni/AndroidCommon/AndroidCommon.cpp b/Source/Android/jni/AndroidCommon/AndroidCommon.cpp
index 73405b6d8e60..887ae4deab09 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 ca8245182d0b..2ab220eac735 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 308fda1f0465..dc642e3efd54 100644
--- a/Source/Android/jni/AndroidCommon/IDCache.cpp
+++ b/Source/Android/jni/AndroidCommon/IDCache.cpp
@@ -43,6 +43,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()
@@ -193,6 +198,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
@@ -268,6 +292,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;
}
@@ -286,6 +320,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 8fd43ea41d4d..32e8fa4e0349 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 53fd9b26998f..1ad11fdc09a9 100644
--- a/Source/Core/Core/IOS/Network/IP/Top.cpp
+++ b/Source/Core/Core/IOS/Network/IP/Top.cpp
@@ -50,6 +50,11 @@
#include
#endif
+#ifdef __ANDROID__
+#include
+#include "jni/AndroidCommon/AndroidCommon.h"
+#endif
+
namespace IOS::HLE::Device
{
enum SOResultCode : s32
@@ -254,8 +259,21 @@ static std::optional GetSystemDefaultInterface()
get_addr(iface->ifa_broadaddr)};
}
}
+#else
+ u32 addr = 0;
+ u32 netmask = 0;
+ u32 gateway = 0;
+ // The thread prevent a stack corruption from JVM->AttachCurrentThread
+ std::thread([&] {
+ addr = GetNetworkIpAddress();
+ const u32 prefix_length = GetNetworkPrefixLength();
+ netmask = (1 << prefix_length) - 1;
+ gateway = GetNetworkGateway();
+ }).join();
+ if (addr || netmask || gateway)
+ return DefaultInterface{addr, netmask, gateway};
#endif
- return {};
+ return std::nullopt;
}
static DefaultInterface GetSystemDefaultInterfaceOrFallback()