出售本站【域名】【外链】

首页 AI人工智能软件 qqAI人工智能 微信AI人工智能 抖音AI人工智能 快手AI人工智能 云控系统 手机AI人工智能

Android 以太网/有线网Ethernet功能开发

2022-02-18

以太网的罪能是允许方法供给硬件接口通过插入网线的模式会见互联网的罪能。接入网线之后,方法可以动态的获与IPDNSGateway等一系列网络属性,咱们也可以手动配购买法的网络属性,运用静态配置参数。Google曾经有一套现成的机制运用有线网,但没有波及有线网配置的罪能,原文次要引见如何Google现有机制的根原上真现静态网络的配置。原文基于高通MSM8953 Android 7.1平台停行开发,通过配置eth0网口的IPDNSGateway三个参数,真现上网罪能,若是其余平台大概非高通平台,可以当做参考。


2. 动态获与网络参数

此局部Google曾经作好,当接入网线之后,正在SystemBar中会显现有线网介入图标(<--->),此时方法曾经接入有线网络,可以一般上网


3. 手动配置网络参数(重点)

首先先来引见一下相关java类:

1frameworks/base/core/java/android/net/IpConfiguration.java

IP形态配置,动态大概是静态,之后会引见

2frameworks/base/core/java/android/net/StaticIpConfiguration.java

静态IP配置相关类,次要用于配置静态IP

3frameworks/base/core/java/android/net/EthernetManager.java

上层配置IP的打点类,可以通过context.getSystemService(Context.ETHERNET_SERVICE)与得。

4frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetServiceImpl.java

通过真现IEthernetManager.aidl接口来办理一些远程的以太网乞求。

5frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java

以太网网络链接的打点类。

详细引见之前,先来看一张简略配置UML的流程图,便捷接下来的解说.

接下来斗劲流程图逐步停行解说。



3.1 输入相关配置信息

咱们原人的名目中是通过配置eth0IPDNSGateway来配置静态网络参数的。可以原人开发相应界面,让用户手动输入相关信息便可。

那一步不波及配置代码,仅仅是获与用户的想要设置的配置信息。


3.2 获与IpConfiguration配置参数

首先咱们须要将相关配置信息转化为StaticIpConfiguration,转化之前,先引见两个枚举类:

public enum IpAssignment { /* Use statically configured IP settings. Configuration can be accessed * with staticIpConfiguration */ STATIC, /* Use dynamically configured IP settigns */ DHCP, /* no IP details are assigned, this is used to indicate * that any existing IP settings should be retained */ UNASSIGNED } public enum ProxySettings { /* No proxy is to be used. Any existing proxy settings * should be cleared. */ NONE, /* Use statically configured proxy. Configuration can be accessed * with httpProxy. */ STATIC, /* no proxy details are assigned, this is used to indicate * that any existing proxy settings should be retained */ UNASSIGNED, /* Use a Pac based proxy. */ PAC }

那两个枚举类型正在IpConfiguration类中,详细做用上面代码局部的注释也写明了。下面是将配置信息转化为StaticIpConfiguration的办法:

private StaticIpConfiguration validateIpConfigFields(String ip,String dns,String gateway) { StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); //analysis ip address Inet4Address inetAddr = getIPv4Address(ip); if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) { return -1; } staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, DEFAULT_PREFIX_LENGTH); //analysis gateway address InetAddress gatewayAddr = getIPv4Address(gateway); if (gatewayAddr == null) { return -1; } if (gatewayAddr.isMulticastAddress()) { return -1; } staticIpConfiguration.gateway = gatewayAddr; //analysis dns address InetAddress dnsAddr = getIPv4Address(dns); if (dnsAddr == null) { return -1; } staticIpConfiguration.dnsServers.add(dnsAddr); return staticIpConfiguration; } private Inet4Address getIPv4Address(String text) { try { return (Inet4Address) NetworkUtils.numericToInetAddress(text); } catch (IllegalArgumentException | ClassCastException e) { Log.e(TAG,"getIPv4Address fail"); return null; } }

此中DEFAULT_PREFIX_LENGTH默许值是24,参考来自于Wifi模块。至此,咱们就将用户输入的IPDNSGateway转化为须要的StaticIpConfiguration

由于最末挪用EthernetManagersetConfiguration函数时通报的参数类型是IpConfiguration,查察StaticIpConfiguration,发现StaticIpConfiguration其真不是IpConfiguration的子类,所以咱们须要正在将StaticIpConfiguration转化为IpConfiguration,查察IpConfiguration代码,发现IpConfiguration的结构函数中含有StaticIpConfiguration参数,此外,咱们可以通过setStaticIpConfiguration扭转IpConfiguration。那里咱们选择前者,间接运用StaticIpConfiguration传入IpConfiguration的结构函数创立IpConfiguration对象,先看一下IpConfiguration的结构函数:

private void init(IpAssignment ipAssignment, ProxySettings proxySettings, StaticIpConfiguration staticIpConfiguration, ProxyInfo httpProxy) { this.ipAssignment = ipAssignment; this.proxySettings = proxySettings; this.staticIpConfiguration = (staticIpConfiguration == null) ? null : new StaticIpConfiguration(staticIpConfiguration); this.httpProxy = (httpProxy == null) ? null : new ProxyInfo(httpProxy); } public IpConfiguration() { init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null); } public IpConfiguration(IpAssignment ipAssignment, ProxySettings proxySettings, StaticIpConfiguration staticIpConfiguration, ProxyInfo httpProxy) { init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy); }

可以看出,无论是有参的结构函数还是无参的结构函数,最末都会挪用IpConfigurationinit函数停行初始化配置。咱们运用的是IpConfiguration中有参的结构函数,此中参数IpAssignmentProxySettings是枚举类型,咱们须要配置静态地址,所以应当传入IpAssignment.STATICProxySettings.STATIC,第三个参数传入StaticIpConfiguration,第四个参数ProxyInfo传入空便可,不须要设置代办代理。

mIpAssignment = IpAssignment.STATIC; mProxySettings = ProxySettings.STATIC; mStaticIpConfiguration = validateIpConfigFields(ip,dns,gateway); // 留心此处的参数应准确配置 IpConfiguration ipconfig = new IpConfiguration(mIpAssignment,mProxySettings,mStaticIpConfiguration,null);


3.3 通过Ethernet发出配置号令

获与IpConfiguration之后,咱们就可以挪用EthernetManagersetConfiguration初步停行静态网络配置:

/** * Set Ethernet configuration. */ public void setConfiguration(IpConfiguration config) { try { mService.setConfiguration(config); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }

查察设置代码,函数会挪用mServicesetConfiguration并且可能会抛出RemoteException。注明那一收配应当是远程aidl的挪用,跟踪代码发现mService的类型为EthernetServiceImpl,并且真现了IEthernetManager.aidl接口。


3.4 EthernetServiceImpl办理乞求 查察 EthernetServiceImpl中的设置函数:
/** * Set Ethernet configuration */ @Override public void setConfiguration(IpConfiguration config) { if (!mStarted.get()) { Log.w(TAG, "System isn't ready enough to change ethernet configuration"); } enforceConnectivityInternalPermission(); synchronized (mIpConfiguration) { mEthernetConfigStore.writeIpAndProxyConfigurations(config); // TODO: this does not check proxy settings, gateways, etc. // Fix this by making IpConfiguration a complete representation of static configuration. if (!config.equals(mIpConfiguration)) { mIpConfiguration = new IpConfiguration(config); mTracker.stop(); mTracker.start(mContext, mHandler); } } }

代码中EthernetConfigStore将会把IpConfiguration的配置信息写入配置文件。进入EthernetConfigStore发现writeIpAndProxyConfigurations最后会挪用EthernetConfigStore父类writeIpAndProxyConfigurations办法将配置信息写入配置文件。

之后判断当前地址能否跟配置地址一样,若纷比方样,则停行新地址的配置,由于配置信息曾经通过EthernetConfigStore写入配置文件,mTracker也即EthernetNetworkFactory就会重启当前网络。那局部的逻辑代码都是Google已有的代码,那里不继续跟踪。

注:有时候EthernetNetworkFactory重启网络之后发现配置信息没有生效,我逢到那种状况后,发现此时须要重启eth0网口。重启网口的罪能将会正在下面的文章里引见。


4 监听网线的插拔 开发时,咱们须要见监听以太网的形态厘革,依据形态厘革更新界面显示大概是作一些其余的收配。由于上层代码真际收配的是 EthernetManager类,所以理所应当先去EthernetManger中查察有没有类似接口,大概回调函数之类可以监听网口厘革的罪能,查察EthernetManager,咱们发现有如下的接口:
/** * A listener interface to receive notification on changes in Ethernet. */ public interface Listener { /** * Called when Ethernet port's availability is changed. * @param isAvailable {@code true} if one or more Ethernet port exists. */ public void onAvailabilityChanged(boolean isAvailable); }

评释中说此接口可以承受以太网厘革的通知。正在真际使用时,发现插入网线和拔出网线简曲能够承遭到通知,注明那个接口正是咱们须要的。查察代码发现,要运用那个接口,应当先挪用addListener将真现该接口的子类参预到一个ArrayList的通知列表里面,那注明咱们可以正在差异的处所承受以太网形态厘革的通知。

/** * Adds a listener. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. */ public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } mListeners.add(listener); if (mListeners.size() == 1) { try { mService.addListener(mServiceListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }

从上面代码可以看到,通报的参数被添加到了mListeners中,并且将mServiceListener添加到EthernetServiceImpl的远程监听接口中去。mServiceListener代码如下:

private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { @Override public void onAvailabilityChanged(boolean isAvailable) { mHandler.obtainMessage( MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, null).sendToTarget(); } };

若系统检测到以太网形态发作厘革,则会通过挪用mServiceListener来停行广播通知,接着正在mHandler中会循坏方便mListeners列表中的监听对象,凡是注册了监听接口的类都会支到通知音讯。



5. 网口的打开取封锁

有时候咱们须要正在不拔出网线的同时封锁上网的罪能,那个时候处置惩罚惩罚方安便是将网口封锁,等到允许上网时再打开网口,接下来就来引见网口的打开取封锁收配。

查察EthernetNetworkFactory的代码可以发现有那样一个函数和之前一样,咱们先到EthernetManager中查察有没有曾经作好的罪能可以供咱们挪用。很遗憾的是,EthernetManager并无真现开关网口的罪能。由于EthernetManager不是最末打点以太网的打点类,只是一个供给上层接口的一个中间类,所以要想查察以太网的所以罪能,咱们应当去查找以太网的打点类EthernetNetworkFactory

查察EthernetNetworkFactory的代码可以发现有那样一个函数:

/** * Updates interface state variables. * Called on link state changes or on startup. */ private void updateInterfaceState(String iface, boolean up) { Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")+" , mIface : "+mIface); if (!mIface.equals(iface)) { return; } Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")); synchronized(this) { mLinkUp = up; mNetworkInfo.setIsAvailable(up); if (!up) { // Tell the agent we're disconnected. It will call disconnect(). mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); stopIpProvisioningThreadLocked(); } updateAgent(); // set our score lower than any network could go // so we get dropped. TODO - just unregister the factory // when link goes down. mFactory.setScoreFilter(up ? NETWORK_SCORE : -1); } }

那正是咱们想要的罪能,所以那个罪能其真也是曾经作好的,但是他是private类型的函数,注明Google其真不想将那个罪能公然出来。函数的第一个参数是想要打开或封锁的网口称呼,第二个参数讲明是打开还是封锁,true默示打开,false默示封锁。

既然曾经有了罪能,咱们只须要挪用便可,详细如何挪用,咱们可以模仿配置静态IP的办法,从EthernetManager初步,到EthernetNetworkFactory完毕,将那个历程作成一个范例的罪能。

首先咱们正在 EthernetManager中添加一个函数updateIface
/* * up and down eth0 */ public void updateIface(String iface,boolean up){ try { mService.updateIfaceState(iface,up); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }

此时须要正在EthernetServiceImpl中添加函数updateIfaceState

@Override public void updateIfaceState(String iface,boolean up){ mTracker.changeEthernetState(iface,up); }

Override注讲解明那是重写函数,EthernetServiceImpl承继自IEthernetManager.Stub,所以咱们须要正在对应的IEthernetManager.aidl接口文件中参预updateIfaceState声明,如下所示:

// IethernetManager.aidl interface IEthernetManager { IpConfiguration getConfiguration(); void setConfiguration(in IpConfiguration config); boolean isAvailable(); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); void updateIfaceState(String iface,boolean up); }

那里之后会挪用mTracker.changeEthernetState函数正在EthernetNetworkFactory创立函数changeEthernetState

public void changeEthernetState(String iface,boolean state){ Log.i(TAG,"changeEthernetState : iface : "+iface+" , state : "+state); updateInterfaceState(iface,state); }

到此完毕,从EthernetManagerEthernetNetworkFactory中对于网口开关的罪能就作完了,咱们只须要挪用EthernetManager中的updateIface函数就能真现网口的打开取封锁罪能。



6 监听网线拔出

之前正在第四节中引见过监听网线的插拔罪能,第五节中引见了正在不拔网线的状况下打开取封锁网口,那个时候就会逢到一个问题,这便是我无奈准确的监听到网线的拔出。真际收配中会发现,打开取封锁网口是,监听器监听同样会被挪用,但是此时我并无拔出网线。换一个说法便是,网口的打开取封锁真际上模拟的便是网线的插拔罪能。

这此时我就须要准确区离开网口的封锁取网线的拔出那两种状况。

查问EthernetNetworkFactory代码可以发现有一个内部类可以监听到网线的插入取拔出:

private class InterfaceObserver extends BaseNetworkObserver { @Override public void interfaceLinkStateChanged(String iface, boolean up) { updateInterfaceState(iface, up); } @Override public void interfaceAdded(String iface) { maybeTrackInterface(iface); } @Override public void interfaceRemoved(String iface) { stopTrackingInterface(iface); } }

此中interfaceAdded默示网线的插入,interfaceRemoved默示网线的拔出。为了共同系统的本生代码构造,咱们可以正在EthernetManagerListener接口中添加一个新函数声明,添加后的Listener接口如下:

/** * A listener interface to receive notification on changes in Ethernet. */ public interface Listener { /** * Called when Ethernet port's availability is changed. * @param isAvailable {@code true} if one or more Ethernet port exists. */ public void onAvailabilityChanged(boolean isAvailable); /* *Called when network wire take out */ public void onEthernetIfaceRemove(); }

监听的注册流程重EthernetManageraddListener,到EthernetServiceImpl中的addListener时,曾经将其注册到了一个RemoteCallList的列表中,正在通过结构mTacker是将监听列表传给了EthernetNetworkFactory。所以咱们只须要正在EthernetNetworkFactory真现通知网线拔出就可以了。

详细代码如下: private void notifyListenersRemoved(){ int n = mListeners.beginBroadcast(); Log.i("SIMCOMIP","notifyListenersRemoved state listener size : "+n); for (int i = 0; i < n; i++) { try { mListeners.getBroadcastItem(i).onEthernetIfaceRemove(); } catch (RemoteException e) { // Do nothing here. } } mListeners.finishBroadcast(); }

首先,添加一个通知所有监听者网线拔出的函数,之后咱们就可以正在前面提到的InterfaceObserverinterfaceRemoved函数中挪用一下就可以了:

private class InterfaceObserver extends BaseNetworkObserver { @Override public void interfaceLinkStateChanged(String iface, boolean up) { updateInterfaceState(iface, up); } @Override public void interfaceAdded(String iface) { maybeTrackInterface(iface); } @Override public void interfaceRemoved(String iface) { stopTrackingInterface(iface); notifyListenersRemoved(); } }
7. SystsemUI同步更新

上层的SystemUI显示图标及更新是通过NetworkControllerImpl.java文件完成,详细可以原人查察代码,那里不作解析了。

热门文章

随机推荐

友情链接: 永康物流网 本站外链出售 义乌物流网 本网站域名出售 手机靓号-号码网