对于Android TV来说,运用以太网进行上网也是网络运用场景之一,可是Google一直都没有较为杰出的完成静态网络装备的办法,正好近期有Android S 的有线网络适配的需求,特此将一些适配办法以及疑问记载一下(如有缺乏,能够请各位大佬留言谈论补充纠错)。
Android 版别影响
首要便是Android 11 与 12 的有线网络版别差距仍是比较大的,所以假如之前只在11上面适配过
,那么对于12来说,适配仍是需求花费一点功夫,详细的差异在之后的部分会记载,可是12与13的有线网络差异就较小了,并且看起来,13的以太网接口以及逻辑比12来说更为完善。
#装备以太网所需求的类
装备以太网所需求的java类大概有以下几个,其实这几个类从Android9开始便是以太网装备的首要java类了
-
frameworks/base/core/java/android/net/EthernetManager.java
EthernetManager.java此是上层办理以太网的类,咱们常通过context.getSystemService(Context.ETHERNET_SERVICE)取得他的实例对象
-
packages/modules/Connectivity/framework/src/android/net/IpConfiguration.java
这个IpConfiguration.java类存在的目录就非常奇怪了,之前我有做过的Android 9 版别这个类分明在frameworks/base/core/java/android/net/IpConfiguration.java 这个途径才对,(可能是我没去官网看版别差异的原因)所以暂时将他列为Android12网络的一个差异吧,
书回正题,这个类首要便是用来装备IP状态的,包括动态和静态 -
packages/modules/Connectivity/framework/src/android/net/StaticIpConfiguration.java
望文生义,这个类首要便是用来装备静态IP的,这个类之前也是在frameworks/base/core/java/android/net/途径下,12里边也移到了packages/modules/Connectivity/framework/src/android/net/下
其实到这儿,对于咱们应用app来说现已能够包括了所有的以太网运用类了,可是对于framework开发有线网络来说,原生Android已有的装备办法,无法满足咱们的需求,所以还需求对Ethernet_service进行修正,以下是Ethernet_server所包括的类
-
Android/frameworks/base/core/java/android/net/IEthernetManager.aidl
EthernetManager.java此类与EthernetServiceImpl.java通信的AIDL文件,类似于WMS的工作办法,其实需求一个service跨进程进行通信
-
Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java
AIDL完成的完成类,便是Ethernet_service的详细完成
-
Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
以太网网络连接的办理类
-
Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java
EthernetTracker中首要做了以下两件事 :
1. 首要更新 ip config的,这个和静态ip相关;
2. 根据iface,调用addInterface创建interface
获取IP参数修正记载
通过查阅源码,发现,咱们设置IP后,所需求的网络参数如: DNS,gateway,IPaddress,netmask 这些都无法直接获取,所以,咱们首要的修正便是直接获取当前的ip参数,以及增加有线网络的开关
Android/frameworks/base/core/java/android/net/EthernetManager.java中增加
/**
* Indicates whether the interface is up.
*
* @param iface Ethernet interface name
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isInterfaceup(String iface) {
try {
return mService.isInterfaceup(iface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
*/
@UnsupportedAppUsage
public String getIpAddress(String iface) {
try {
return mService.getIpAddress(iface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
*/
@UnsupportedAppUsage
public String getNetmask(String iface) {
try {
return mService.getNetmask(iface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
*/
@UnsupportedAppUsage
public String getGateway(String iface) {
try {
return mService.getGateway(iface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
*/
@UnsupportedAppUsage
public String getDns(String iface) {
try {
return mService.getDns(iface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
Android/frameworks/base/core/java/android/net/IEthernetManager.aidl 增加AIDL通信
boolean isInterfaceup(String iface);
String getIpAddress(String iface);
String getNetmask(String iface);
String getGateway(String iface);
String getDns(String iface);
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java 中增加getIpAddress,getNetmask,getGateway,getDns的完成逻辑。
diff --git a/Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java b/Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
index 28b24f1fb1..2dc9b0f908 100644
--- a/Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
+++ b/Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -22,10 +22,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.EthernetManager;
import android.net.EthernetNetworkSpecifier;
import android.net.IpConfiguration;
import android.net.IpConfiguration.IpAssignment;
import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
@@ -33,6 +35,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
+import android.net.RouteInfo;
import android.net.ip.IIpClient;
import android.net.ip.IpClientCallbacks;
import android.net.ip.IpClientUtil;
@@ -47,11 +50,16 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.Inet4AddressUtils;
import java.io.FileDescriptor;
+import java.lang.reflect.Method;
+import java.net.Inet4Address;
+import java.net.InetAddress;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+
/**
* {@link NetworkFactory} that represents Ethernet networks.
*
@@ -69,6 +77,9 @@ public class EthernetNetworkFactory extends NetworkFactory {
new ConcurrentHashMap<>();
private final Handler mHandler;
private final Context mContext;
+ private EthernetManager mEthernetManager;
+
+ private static boolean[] mIfaceStatus = new boolean[2];
public static class ConfigurationException extends AndroidRuntimeException {
public ConfigurationException(String msg) {
@@ -83,6 +94,7 @@ public class EthernetNetworkFactory extends NetworkFactory {
mContext = context;
setScoreFilter(NETWORK_SCORE);
+ mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);
}
@Override
@@ -104,8 +116,9 @@ public class EthernetNetworkFactory extends NetworkFactory {
}
if (++network.refCount == 1) {
- network.start();
+ //network.start();
}
+ Log.w(TAG, "needNetworkFor, network.refCount = " +network.refCount);
}
@Override
@@ -117,8 +130,9 @@ public class EthernetNetworkFactory extends NetworkFactory {
}
if (--network.refCount == 0) {
- network.stop();
+ //network.stop();
}
+ Log.w(TAG, "releaseNetworkFor, network.refCount = " +network.refCount);
}
/**
@@ -197,6 +211,14 @@ public class EthernetNetworkFactory extends NetworkFactory {
Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up);
}
+ if (ifaceName.equals("eth0")) {
+ Log.i(TAG, " mIfaceStatus[0] = up");
+ mIfaceStatus[0] = up;
+ }
+ if (ifaceName.equals("eth1")){
+ Log.i(TAG, "mIfaceStatus[1] = up");
+ mIfaceStatus[1] = up;
+ }
NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
return iface.updateLinkState(up);
}
@@ -204,6 +226,121 @@ public class EthernetNetworkFactory extends NetworkFactory {
boolean hasInterface(String interfacName) {
return mTrackingInterfaces.containsKey(interfacName);
}
+
+ // ADD BEGIN
+ boolean isInterfaceup(String interfacName) {
+ if (interfacName.equals("eth0"))
+ return mIfaceStatus[0];
+ else if (interfacName.equals("eth1"))
+ return mIfaceStatus[1];
+ else
+ return false;
+ }
+
+ String getIpAddress(String iface) {
+ IpConfiguration config = mEthernetManager.getConfiguration(iface);
+ if (config.getIpAssignment() == IpAssignment.STATIC) {
+ return config.getStaticIpConfiguration().getIpAddress().getAddress().getHostAddress();
+ } else {
+ NetworkInterfaceState netState = mTrackingInterfaces.get(iface);
+ if (null != netState) {
+ for (LinkAddress l : netState.mLinkProperties.getLinkAddresses()) {
+ InetAddress source = l.getAddress();
+ //Log.d(TAG, "getIpAddress: " + source.getHostAddress());
+ if (source instanceof Inet4Address) {
+ return source.getHostAddress();
+ }
+ }
+ }
+ }
+ return "";
+ }
+
+ private String prefix2netmask(int prefix) {
+ // convert prefix to netmask
+ if (true) {
+ int mask = 0xFFFFFFFF << (32 - prefix);
+ //Log.d(TAG, "mask = " + mask + " prefix = " + prefix);
+ return ((mask>>>24) & 0xff) + "." + ((mask>>>16) & 0xff) + "." + ((mask>>>8) & 0xff) + "." + ((mask) & 0xff);
+ } else {
+ int hostAddress = Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefix);
+ return Inet4AddressUtils.intToInet4AddressHTL(hostAddress).getHostName();
+ }
+ }
+
+ String getNetmask(String iface) {
+ IpConfiguration config = mEthernetManager.getConfiguration(iface);
+ if (config.getIpAssignment() == IpAssignment.STATIC) {
+ return prefix2netmask(config.getStaticIpConfiguration().getIpAddress().getPrefixLength());
+ } else {
+ NetworkInterfaceState netState = mTrackingInterfaces.get(iface);
+ if (null != netState) {
+ for (LinkAddress l : netState.mLinkProperties.getLinkAddresses()) {
+ InetAddress source = l.getAddress();
+ if (source instanceof Inet4Address) {
+ return prefix2netmask(l.getPrefixLength());
+ }
+ }
+ }
+ }
+ return "";
+ }
+
+ String getGateway(String iface) {
+ IpConfiguration config = mEthernetManager.getConfiguration(iface);
+ if (config.getIpAssignment() == IpAssignment.STATIC) {
+ return config.getStaticIpConfiguration().getGateway().getHostAddress();
+ } else {
+ NetworkInterfaceState netState = mTrackingInterfaces.get(iface);
+ if (null != netState) {
+ for (RouteInfo route : netState.mLinkProperties.getRoutes()) {
+ if (route.hasGateway()) {
+ InetAddress gateway = route.getGateway();
+ Object isIPv4Default = invokeMethodNoParameter(route, "isIPv4Default");
+ if (null != isIPv4Default && (Boolean)isIPv4Default) {
+ return gateway.getHostAddress();
+ }
+ }
+ }
+ }
+ }
+ return "";
+ }
+
+ private Object invokeMethodNoParameter(Object object, String methodName) {
+ try {
+ Method method = object.getClass().getDeclaredMethod(methodName);
+ method.setAccessible(true);
+ return method.invoke(object);
+ //return method.invoke(object, paramTypes);
+ } catch (Exception e) {
+ Log.e(TAG, "invokeMethod->methodName:" + methodName + ", " + e);
+ }
+ return null;
+ }
+
+ /*
+ * return dns format: "8.8.8.8,4.4.4.4"
+ */
+ String getDns(String iface) {
+ String dns = "";
+ IpConfiguration config = mEthernetManager.getConfiguration(iface);
+ if (config.getIpAssignment() == IpAssignment.STATIC) {
+ for (InetAddress nameserver : config.getStaticIpConfiguration().getDnsServers()) {
+ dns += nameserver.getHostAddress() + ",";
+ }
+ } else {
+ NetworkInterfaceState netState = mTrackingInterfaces.get(iface);
+ if (null != netState) {
+ for (InetAddress nameserver : netState.mLinkProperties.getDnsServers()) {
+ dns += nameserver.getHostAddress() + ",";
+ }
+ }
+ }
+ return dns;
+ }
+
+ //ADD END
void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
NetworkInterfaceState network = mTrackingInterfaces.get(iface);
@@ -382,7 +519,7 @@ public class EthernetNetworkFactory extends NetworkFactory {
}
void setIpConfig(IpConfiguration ipConfig) {
- if (Objects.equals(this.mIpConfig, ipConfig)) {
+ /* if (Objects.equals(this.mIpConfig, ipConfig)) {
if (DBG) Log.d(TAG, "ipConfig have not changed,so ignore setIpConfig");
return;
}
@@ -390,6 +527,9 @@ public class EthernetNetworkFactory extends NetworkFactory {
if (mNetworkAgent != null) {
restart();
}
+ */
+ this.mIpConfig = ipConfig;
+ restart();
}
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java 中增加从EthernetTracker中获取参数的办法:
--- a/Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java
+++ b/Android/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java
@@ -141,6 +141,61 @@ public class EthernetServiceImpl extends IEthernetManager.Stub {
return mTracker.isTrackingInterface(iface);
}
+ @Override
+ public boolean isInterfaceup(String iface) {
+ enforceAccessPermission();
+
+ if (mTracker.isRestrictedInterface(iface)) {
+ enforceUseRestrictedNetworksPermission();
+ }
+
+ return mTracker.isInterfaceup(iface);
+ }
+
+ @Override
+ public String getIpAddress(String iface) {
+ enforceAccessPermission();
+
+ if (mTracker.isRestrictedInterface(iface)) {
+ enforceUseRestrictedNetworksPermission();
+ }
+
+ return mTracker.getIpAddress(iface);
+ }
+
+ @Override
+ public String getNetmask(String iface) {
+ enforceAccessPermission();
+
+ if (mTracker.isRestrictedInterface(iface)) {
+ enforceUseRestrictedNetworksPermission();
+ }
+
+ return mTracker.getNetmask(iface);
+ }
+
+ @Override
+ public String getGateway(String iface) {
+ enforceAccessPermission();
+
+ if (mTracker.isRestrictedInterface(iface)) {
+ enforceUseRestrictedNetworksPermission();
+ }
+
+ return mTracker.getGateway(iface);
+ }
+
+ @Override
+ public String getDns(String iface) {
+ enforceAccessPermission();
+
+ if (mTracker.isRestrictedInterface(iface)) {
+ enforceUseRestrictedNetworksPermission();
+ }
+
+ return mTracker.getDns(iface);
+ }
+
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java中完成对EthernetFactory的实例化,并完成getIP参数的办法
+ boolean isInterfaceup(String iface) {
+ return mFactory.isInterfaceup(iface);
+ }
+
+ String getIpAddress(String iface) {
+ return mFactory.getIpAddress(iface);
+ }
+
+ String getNetmask(String iface) {
+ return mFactory.getNetmask(iface);
+ }
+
+ String getGateway(String iface) {
+ return mFactory.getGateway(iface);
+ }
+
+ String getDns(String iface) {
+ return mFactory.getDns(iface);
+ }
+
做完以上过程后,咱们的EthernetManager中就有了isInterfaceup,getIpAddress,getNetmask,getGateway,getDns办法,能够直接获取动态或许静态的ip参数,就不需求再对当前的ipconfiguration进行剖析,便利许多。
增加以太网开关
安卓13的更改简略阅读
阅读了Android 13 的代码,发现其实在13版别中现已增加了相关的代码,而且13更是将EthernetManager.java移动到了packages\modules\Connectivity\framework-t\src\android\net\EthernetManager.java这个途径下,与framework进行了别离,乃至wifi 、蓝牙、热点 之前 framework 的源码都移动到了下面的package目录:
packages\modules\Connectivity\
可是12仍是在framework中,所以暂时没有深入研究,仅仅看到有开关的相关办法
@RequiresPermission(anyOf = {NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,android.Manifest.permission.NETWORK_STACK,android.Manifest.permission.NETWORK_SETTINGS})
@SystemApi(client = MODULE_LIBRARIES)
public void setEthernetEnabled(boolean enabled) {
try {
mService.setEthernetEnabled(enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
以此推测,EthernetServiceImpl.java中应该是有相关的开关办法,然后搜索EthernetServiceImpl.java,发现,这个类也换了位置->packages/modules/Connectivity/service-t/src/com/android/server/ethernet/EthernetTracker.java,/service-t/是用来存放AIDL的完成service的目录,详细完成开关的流程为:
graph TD
mService.setEthernetEnabled--> mTracker.setEthernetEnabled--> trackAvailableInterfaces-->
maybeTrackInterface-->addInterface-->NetdUtils.setInterfaceUp
大致的流程便是这样,最终仍是调用了之前就存在的NetdUtils.setInterfaceUp(mNetd, iface);办法
回过头来看12代码,由于没有开关,由此挑选什么做法就看自己决定了,首要榜首种办法便是直接比较暴力的开关(这个我也是看到有芯片厂商这样做,直接借鉴一下^^).
Ethernet以太网开关
1. 厂商的做法便是运用到这个AIDL INetworkManagementService.aidl
,这个里边有
/**
* Set interface up
*/
void setInterfaceUp(String iface);
咱们能够直接实例化这个aidl对象,然后在场景下调用这个办法,进行开关。
private INetworkManagementService mNMService;
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
mNMService = INetworkManagementService.Stub.asInterface(b);
try {
mNMService.setInterfaceDown(mIfaceName);
mNMService.setInterfaceUp(mIfaceName);
} catch (RemoteException e) { // NwService throws runtime exceptions for errors
Log.e(TAG, "Settings: can't bring interface restart - " + e);
}
2. 另一种做法便是在EthernetTracker.java 中运用此办法mNMService.setInterfaceUp("eth0");
(由于咱们的产品只要一个网口,所以,固定是eth0,正常应该传参^^)
做完这些咱们的需求基本就完成了,至于UI部分以后有机会再说吧^^
问题
做完这些之后,通过自测,发现设置静态IP居然在关机开机之后有概率读取不到IP信息 !!!可是开关一下自己写的以太网开关就又能读到了??回看代码觉得写的也没问题吧...后面发现,厂商在TVsettings里边设置静态IP之后开关了一下以太网接口,测验加上这个patch,问题算是处理了.(可是不知道为什么RK的不必开关啊??)
总结
其实许多芯片厂商都会把以太网的一整套办法写好(我见过的只要几个没有,各家的写法也都不尽相同,可是好在都有写),由于Android早就现已有完整的以太网流程,尽管没有开发出来配套的静态接口,可是现已算比较成熟的功用了。最首要便是了解EthernetServiceImpl&EthernetTracker&EthernetNetworkFactory这三个类的读取和装备就能够,至于一整套(从下到上)的流程,还需求去瞅瞅^^ 最终,感谢aospxref.com/