Skip to content

Commit

Permalink
IP/Top: Add Android network interface
Browse files Browse the repository at this point in the history
  • Loading branch information
sepalani committed Oct 24, 2020
1 parent 47059f6 commit beb7ae2
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 1 deletion.
1 change: 1 addition & 0 deletions Source/Android/app/src/main/AndroidManifest.xml
Expand Up @@ -19,6 +19,7 @@

<uses-feature android:glEsVersion="0x00030000"/>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
Expand Down
@@ -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<LinkAddress> 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<RouteInfo> 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;
}
}
21 changes: 21 additions & 0 deletions Source/Android/jni/AndroidCommon/AndroidCommon.cpp
Expand Up @@ -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());
}
3 changes: 3 additions & 0 deletions Source/Android/jni/AndroidCommon/AndroidCommon.h
Expand Up @@ -14,3 +14,6 @@ std::vector<std::string> 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();
35 changes: 35 additions & 0 deletions Source/Android/jni/AndroidCommon/IDCache.cpp
Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<jclass>(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;
}

Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions Source/Android/jni/AndroidCommon/IDCache.h
Expand Up @@ -45,4 +45,9 @@ jclass GetContentHandlerClass();
jmethodID GetContentHandlerOpenFd();
jmethodID GetContentHandlerDelete();

jclass GetNetworkHelperClass();
jmethodID GetNetworkHelperGetNetworkIpAddress();
jmethodID GetNetworkHelperGetNetworkPrefixLength();
jmethodID GetNetworkHelperGetNetworkGateway();

} // namespace IDCache
20 changes: 19 additions & 1 deletion Source/Core/Core/IOS/Network/IP/Top.cpp
Expand Up @@ -50,6 +50,11 @@
#include <unistd.h>
#endif

#ifdef __ANDROID__
#include <thread>
#include "jni/AndroidCommon/AndroidCommon.h"
#endif

namespace IOS::HLE::Device
{
enum SOResultCode : s32
Expand Down Expand Up @@ -254,8 +259,21 @@ static std::optional<DefaultInterface> 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()
Expand Down

0 comments on commit beb7ae2

Please sign in to comment.