精华内容
下载资源
问答
  • android 7.1 分享以太网,增加状态栏分享开关,修复关闭以太网分享后无法使用以太网口的bug
  • Android 7.1 以太网设置 IP @hide EthernetManager 通过 android.net.EthernetManager#setConfiguration 可以设置以太网 IP 信息,可惜 EthernetManager 无法直接调用。 /** * A class representing the IP ...

    @hide EthernetManager

    通过 android.net.EthernetManager#setConfiguration 可以设置以太网 IP 信息,可惜 EthernetManager 无法直接调用。

    /**
     * A class representing the IP configuration of the Ethernet network.
     *
     * @hide
     */
    public class EthernetManager {
    	...
        /**
         * Set Ethernet configuration.
         */
        public void setConfiguration(IpConfiguration config) {
            try {
                mService.setConfiguration(config);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        ...
    }
    

    反射调用 setConfiguration 方法

    DHCP 配置

    步骤:

    1. 实例化 IpConfiguration() 对象 ipConfiguration
    2. 设置 ipConfiguration.ipConfiguration = xxx
    3. 设置 ipConfiguration.ipConfiguration = xxx
    4. 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
    /**
      * 调用 EthernetManager.setConfiguration(IpConfiguration config) 设置 DHCP
      *
      * 步骤:
      * - 实例化 IpConfiguration() 对象 ipConfiguration
      * - 设置 ipConfiguration.ipConfiguration = xxx
      * - 设置 ipConfiguration.ipConfiguration = xxx
      * - 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
      */
     @WorkerThread
     fun setDynamicIp(ethernetManager: EthernetManager): Boolean {
         try {
             // 获取 IpConfiguration 对象
             val ipConfigurationCls = Class.forName("android.net.IpConfiguration")
             val ipConfigurationEnum = getEnumMap(ipConfigurationCls)
             val ipConfiguration = ipConfigurationCls.newInstance()
    
             // 设置 ipConfiguration.ipAssignment 为 IpAssignment.DHCP
             val ipAssignment = ipConfigurationCls.getField("ipAssignment")
             ipAssignment.set(ipConfiguration, ipConfigurationEnum["IpAssignment.DHCP"])
    
             // 设置 ipConfiguration.proxySettings 为 ProxySettings.NONE
             val proxySettings = ipConfigurationCls.getField("proxySettings")
             proxySettings.set(ipConfiguration, ipConfigurationEnum["ProxySettings.NONE"])
    
             // 调用 ethernetManager.setConfiguration(ipConfiguration) 设置 DHCP
             val setConfigurationMethod = ethernetManager.javaClass.getDeclaredMethod(
                 "setConfiguration", ipConfiguration.javaClass
             )
             setConfigurationMethod.invoke(ethernetManager, ipConfiguration)
             return true
         } catch (e: Exception) {
             e.printStackTrace()
             return false
         }
     }
    
    /**
     * 获取 Class 中枚举类键值对
     *
     * 注:key = 枚举类名 + 枚举名
     *    value = 枚举
     */
    private fun getEnumMap(ipConfigurationCls: Class<*>): Map<String, Any> {
        val enumMap: MutableMap<String, Any> = HashMap()
        val enumClasses = ipConfigurationCls.declaredClasses
        for (enumClass in enumClasses) {
            val enumConstants = enumClass.enumConstants ?: continue
            for (enumConstant in enumConstants) {
                // 枚举 Class 名 + 枚举名 = key
                enumMap[enumClass.simpleName + "." + enumConstant.toString()] = enumConstant
            }
        }
        return enumMap
    }
    

    Static IP 配置

    步骤:

    1. 实例化 StaticIpConfiguration 对象 staticIpConfiguration
      1.1. 设置 staticIpConfiguration.ipAddress = xxx
      1.2. 设置 staticIpConfiguration.gateway = xxx
      1.3. 设置 staticIpConfiguration.domains = xxx
      1.4. 设置 staticIpConfiguration.dnsServers = xxx
    2. 实例化 IpConfiguration() 对象 ipConfiguration
      2.1. 设置 ipConfiguration.staticIpConfiguration = staticIpConfiguration
      2.2. 设置 ipConfiguration.ipAssignment = xxx
      2.3. 设置 ipConfiguration.proxySettings = xxx
      2.4. 设置 ipConfiguration.httpProxy = xxx
    3. 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
    /**
      * 调用 EthernetManager.setConfiguration(IpConfiguration config) 设置静态 IP
      *
      * 步骤:
      * - 实例化 StaticIpConfiguration 对象 staticIpConfiguration
      *     - 设置 staticIpConfiguration.ipAddress = xxx
      *     - 设置 staticIpConfiguration.gateway = xxx
      *     - 设置 staticIpConfiguration.domains = xxx
      *     - 设置 staticIpConfiguration.dnsServers = xxx
      * - 实例化 IpConfiguration() 对象  ipConfiguration
      *     - 设置 ipConfiguration.staticIpConfiguration = staticIpConfiguration
      *     - 设置 ipConfiguration.ipAssignment = xxx
      *     - 设置 ipConfiguration.proxySettings = xxx
      *     - 设置 ipConfiguration.httpProxy = xxx
      * - 调用 ethernetManager.setConfiguration(ipConfiguration) 完成设置
      */
     @WorkerThread
     fun setStaticIp(
         ethernetManager: EthernetManager,
         ip: String,
         mask: String,
         gateway: String,
         dns: String
     ): Boolean {
         try {
             // 获取 StaticIpConfiguration 对象
             val staticIpConfiguration = newStaticIpConfiguration(ip, mask, gateway, dns)
    
             // 获取 IpConfiguration 对象
             val ipConfiguration = newIpConfiguration(staticIpConfiguration)
    
             // 通过 setConfiguration 方法设置静态 IP
             val setConfigurationMethod = ethernetManager.javaClass.getDeclaredMethod(
                 "setConfiguration", ipConfiguration.javaClass
             )
             setConfigurationMethod.invoke(ethernetManager, ipConfiguration)
             return true
         } catch (e: Exception) {
             e.printStackTrace()
             return false
         }
     }
    
     /**
      * 获取 IpConfiguration 实例
      */
     private fun newIpConfiguration(staticIpConfiguration: Any): Any {
         // 获取 IpConfiguration 对象
         val ipConfigurationCls = Class.forName("android.net.IpConfiguration")
         val ipConfigurationEnum = getEnumMap(ipConfigurationCls)
         val ipConfiguration = ipConfigurationCls.newInstance()
    
         // 设置 ipConfiguration.staticIpConfiguration 为 staticIpConfiguration
         val staticIpConfigurationField = ipConfigurationCls.getField("staticIpConfiguration")
         staticIpConfigurationField[ipConfiguration] = staticIpConfiguration
    
         // 设置 ipConfiguration.ipAssignment 为 IpAssignment.STATIC
         val ipAssignment = ipConfigurationCls.getField("ipAssignment")
         ipAssignment[ipConfiguration] = ipConfigurationEnum["IpAssignment.STATIC"]
    
         // 设置 ipConfiguration.proxySettings 为 ProxySettings.NONE
         val proxySettings = ipConfigurationCls.getField("proxySettings")
         proxySettings[ipConfiguration] = ipConfigurationEnum["ProxySettings.NONE"]
    
         // 设置 ipConfiguration.httpProxy 为 httpProxy
         val httpProxy = ipConfigurationCls.getField("httpProxy")
         httpProxy[ipConfiguration] = ProxyInfo.buildDirectProxy(null, 0)
         return ipConfiguration
     }
    
     /**
      * 获取 StaticIpConfiguration 实例
      */
     private fun newStaticIpConfiguration(
         ip: String,
         mask: String,
         gate: String,
         dns: String
     ): Any {
         // 获取 StaticIpConfiguration 对象
         val staticIpConfigurationCls = Class.forName("android.net.StaticIpConfiguration")
         val staticIpConfiguration = staticIpConfigurationCls.newInstance()
    
         // 设置 ipAddress
         val ipAddress = staticIpConfigurationCls.getField("ipAddress")
         ipAddress[staticIpConfiguration] = newLinkAddress(ip, mask)
    
         // 设置网关
         val gateway = staticIpConfigurationCls.getField("gateway")
         gateway[staticIpConfiguration] = InetAddress.getByName(gate)
    
         // 设置子网掩码
         val domains = staticIpConfigurationCls.getField("domains")
         domains[staticIpConfiguration] = mask
    
         // 设置 DNS
         val dnsServers = staticIpConfigurationCls.getField("dnsServers")
         val dnsList = dnsServers[staticIpConfiguration] as ArrayList<InetAddress>
         dnsList.add(InetAddress.getByName(dns))
         return staticIpConfiguration
     }
    
     /**
      * 获取 LinkAddress 实例
      */
     private fun newLinkAddress(ip: String, mask: String): Any? {
         val linkAddressCls = Class.forName("android.net.LinkAddress")
         val linkAddressConstructor = linkAddressCls.getDeclaredConstructor(
             InetAddress::class.java,
             Int::class.javaPrimitiveType
         )
         return linkAddressConstructor.newInstance(
             InetAddress.getByName(ip),
             getPrefixLength(mask)
         )
     }
    
     /**
      * 获取长度
      */
     private fun getPrefixLength(mask: String): Int {
         var count = 0
         for (str in mask.split(".")) {
             if (str == "255") {
                 ++count
             }
         }
         return count * 8
     }
    

    注意事项

    以上代码需要是系统应用才能调用,需要在 AndroidManifest 文件中配置 android:sharedUserId=“android.uid.system”。

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        ...
        android:sharedUserId="android.uid.system">
        ...
    </manifest>
    

    参考连接

    展开全文
  • 1. 功能介绍以太网的功能是允许设备提供硬件接口通过插入网线的形式访问互联网的功能。接入网线之后,设备可以动态的获取IP,DNS,Gateway等一系列网络属性,我们也可以手动配置设备的网络属性,使用静态配置参数。...

    1. 功能介绍

    以太网的功能是允许设备提供硬件接口通过插入网线的形式访问互联网的功能。接入网线之后,设备可以动态的获取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,转化之前,先介绍两个枚举类:

    
       
    1. public enum IpAssignment {
    2. /* Use statically configured IP settings. Configuration can be accessed
    3. * with staticIpConfiguration */
    4. STATIC,
    5. /* Use dynamically configured IP settigns */
    6. DHCP,
    7. /* no IP details are assigned, this is used to indicate
    8. * that any existing IP settings should be retained */
    9. UNASSIGNED
    10. }
    
       
    1. public enum ProxySettings {
    2. /* No proxy is to be used. Any existing proxy settings
    3. * should be cleared. */
    4. NONE,
    5. /* Use statically configured proxy. Configuration can be accessed
    6. * with httpProxy. */
    7. STATIC,
    8. /* no proxy details are assigned, this is used to indicate
    9. * that any existing proxy settings should be retained */
    10. UNASSIGNED,
    11. /* Use a Pac based proxy.
    12. */
    13. PAC
    14. }

    这两个枚举类型在IpConfiguration类中,具体作用上面代码部分的注释也写明了。下面是将配置信息转化为StaticIpConfiguration的方法:

    
       
    1. private StaticIpConfiguration validateIpConfigFields(String ip,String dns,String gateway) {
    2. StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
    3. //analysis ip address
    4. Inet4Address inetAddr = getIPv4Address(ip);
    5. if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) {
    6. return - 1;
    7. }
    8. staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, DEFAULT_PREFIX_LENGTH);
    9. //analysis gateway address
    10. InetAddress gatewayAddr = getIPv4Address(gateway);
    11. if (gatewayAddr == null) {
    12. return - 1;
    13. }
    14. if (gatewayAddr.isMulticastAddress()) {
    15. return - 1;
    16. }
    17. staticIpConfiguration.gateway = gatewayAddr;
    18. //analysis dns address
    19. InetAddress dnsAddr = getIPv4Address(dns);
    20. if (dnsAddr == null) {
    21. return - 1;
    22. }
    23. staticIpConfiguration.dnsServers.add(dnsAddr);
    24. return staticIpConfiguration;
    25. }

    
       
    1. private Inet4Address getIPv4Address(String text) {
    2. try {
    3. return (Inet4Address) NetworkUtils.numericToInetAddress(text);
    4. } catch (IllegalArgumentException | ClassCastException e) {
    5. Log.e(TAG, "getIPv4Address fail");
    6. return null;
    7. }
    8. }

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

    由于最终调用EthernetManagersetConfiguration函数时传递的参数类型是IpConfiguration,查看StaticIpConfiguration,发现StaticIpConfiguration并不是IpConfiguration的子类,所以我们需要在将StaticIpConfiguration转化为IpConfiguration,查看IpConfiguration代码,发现IpConfiguration的构造函数中含有StaticIpConfiguration参数,另外,我们可以通过setStaticIpConfiguration改变IpConfiguration。这里我们选择前者,直接使用StaticIpConfiguration传入IpConfiguration的构造函数创建IpConfiguration对象,先看一下IpConfiguration的构造函数:

    
       
    1. private void init(IpAssignment ipAssignment,
    2. ProxySettings proxySettings,
    3. StaticIpConfiguration staticIpConfiguration,
    4. ProxyInfo httpProxy) {
    5. this.ipAssignment = ipAssignment;
    6. this.proxySettings = proxySettings;
    7. this.staticIpConfiguration = (staticIpConfiguration == null) ?
    8. null : new StaticIpConfiguration(staticIpConfiguration);
    9. this.httpProxy = (httpProxy == null) ?
    10. null : new ProxyInfo(httpProxy);
    11. }
    12. public IpConfiguration() {
    13. init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
    14. }
    15. public IpConfiguration(IpAssignment ipAssignment,
    16. ProxySettings proxySettings,
    17. StaticIpConfiguration staticIpConfiguration,
    18. ProxyInfo httpProxy) {
    19. init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
    20. }

    可以看出,无论是有参的构造函数还是无参的构造函数,最终都会调用IpConfigurationinit函数进行初始化配置。我们使用的是IpConfiguration中有参的构造函数,其中参数IpAssignmentProxySettings是枚举类型,我们需要配置静态地址,所以应该传入IpAssignment.STATICProxySettings.STATIC,第三个参数传入StaticIpConfiguration,第四个参数ProxyInfo传入空即可,不需要设置代理。

    
       
    1. mIpAssignment = IpAssignment.STATIC;
    2. mProxySettings = ProxySettings.STATIC;
    3. mStaticIpConfiguration = validateIpConfigFields(ip,dns,gateway); // 注意此处的参数应正确配置
    4. IpConfiguration ipconfig = new IpConfiguration(mIpAssignment,mProxySettings,mStaticIpConfiguration, null);


    3.3 通过Ethernet发出配置命令

    获取IpConfiguration之后,我们就可以调用EthernetManagersetConfiguration开始进行静态网络配置:

    
       
    1. /**
    2. * Set Ethernet configuration.
    3. */
    4. public void setConfiguration(IpConfiguration config) {
    5. try {
    6. mService.setConfiguration(config);
    7. } catch (RemoteException e) {
    8. throw e.rethrowFromSystemServer();
    9. }
    10. }

    查看设置代码,函数会调用mServicesetConfiguration并且可能会抛出RemoteException。说明这一操作应该是远程aidl的调用,跟踪代码发现mService的类型为EthernetServiceImpl,并且实现了IEthernetManager.aidl接口。


    3.4 EthernetServiceImpl处理请求

    查看 EthernetServiceImpl中的设置函数:

    
       
    1. /**
    2. * Set Ethernet configuration
    3. */
    4. @Override
    5. public void setConfiguration(IpConfiguration config) {
    6. if (!mStarted.get()) {
    7. Log.w(TAG, "System isn't ready enough to change ethernet configuration");
    8. }
    9. enforceConnectivityInternalPermission();
    10. synchronized (mIpConfiguration) {
    11. mEthernetConfigStore.writeIpAndProxyConfigurations(config);
    12. // TODO: this does not check proxy settings, gateways, etc.
    13. // Fix this by making IpConfiguration a complete representation of static configuration.
    14. if (!config.equals(mIpConfiguration)) {
    15. mIpConfiguration = new IpConfiguration(config);
    16. mTracker.stop();
    17. mTracker.start(mContext, mHandler);
    18. }
    19. }
    20. }

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

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

    注:有时候EthernetNetworkFactory重启网络之后发现配置信息没有生效,我遇到这种情况后,发现此时需要重启eth0网口。重启网口的功能将会在下面的文章里介绍。


    4 监听网线的插拔

    开发时,我们需要见监听以太网的状态变化,根据状态变化更新界面显示或者是做一些其他的操作。由于上层代码实际操作的是 EthernetManager类,所以理所应该先去EthernetManger中查看有没有类似接口,或者回调函数之类可以监听网口变化的功能,查看EthernetManager,我们发现有如下的接口:

    
       
    1. /**
    2. * A listener interface to receive notification on changes in Ethernet.
    3. */
    4. public interface Listener {
    5. /**
    6. * Called when Ethernet port's availability is changed.
    7. * @param isAvailable {@code true} if one or more Ethernet port exists.
    8. */
    9. public void onAvailabilityChanged(boolean isAvailable);
    10. }

    解释中说此接口可以接受以太网变化的通知。在实际应用时,发现插入网线和拔出网线确实能够接受到通知,说明这个接口正是我们需要的。查看代码发现,要使用这个接口,应该先调用addListener将实现该接口的子类加入到一个ArrayList的通知列表里面,这说明我们可以在不同的地方接受以太网状态变化的通知。

    
       
    1. /**
    2. * Adds a listener.
    3. * @param listener A {@link Listener} to add.
    4. * @throws IllegalArgumentException If the listener is null.
    5. */
    6. public void addListener(Listener listener) {
    7. if (listener == null) {
    8. throw new IllegalArgumentException( "listener must not be null");
    9. }
    10. mListeners.add(listener);
    11. if (mListeners.size() == 1) {
    12. try {
    13. mService.addListener(mServiceListener);
    14. } catch (RemoteException e) {
    15. throw e.rethrowFromSystemServer();
    16. }
    17. }
    18. }

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

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

    若系统检测到以太网状态发生变化,则会通过调用mServiceListener来进行广播通知,接着在mHandler中会循坏便利mListeners列表中的监听对象,凡是注册了监听接口的类都会收到通知消息。



    5. 网口的打开与关闭

    有时候我们需要在不拔出网线的同时关闭上网的功能,这个时候解决方安就是将网口关闭,等到允许上网时再打开网口,接下来就来介绍网口的打开与关闭操作。

    查看EthernetNetworkFactory的代码可以发现有这样一个函数和之前一样,我们先到EthernetManager中查看有没有已经做好的功能可以供我们调用。很遗憾的是,EthernetManager并没有实现开关网口的功能。由于EthernetManager不是最终管理以太网的管理类,只是一个提供上层接口的一个中间类,所以要想查看以太网的所以功能,我们应该去查找以太网的管理类EthernetNetworkFactory

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

    
       
    1. /**
    2. * Updates interface state variables.
    3. * Called on link state changes or on startup.
    4. */
    5. private void updateInterfaceState(String iface, boolean up) {
    6. Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down")+ " , mIface : "+mIface);
    7. if (!mIface.equals(iface)) {
    8. return;
    9. }
    10. Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
    11. synchronized( this) {
    12. mLinkUp = up;
    13. mNetworkInfo.setIsAvailable(up);
    14. if (!up) {
    15. // Tell the agent we're disconnected. It will call disconnect().
    16. mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
    17. stopIpProvisioningThreadLocked();
    18. }
    19. updateAgent();
    20. // set our score lower than any network could go
    21. // so we get dropped. TODO - just unregister the factory
    22. // when link goes down.
    23. mFactory.setScoreFilter(up ? NETWORK_SCORE : - 1);
    24. }
    25. }

    这正是我们想要的功能,所以这个功能其实也是已经做好的,但是他是private类型的函数,说明Google并不想将这个功能公开出来。函数的第一个参数是想要打开或关闭的网口名称,第二个参数表明是打开还是关闭,true表示打开,false表示关闭。

    既然已经有了功能,我们只需要调用即可,具体如何调用,我们可以模仿配置静态IP的方法,从EthernetManager开始,到EthernetNetworkFactory结束,将这个过程做成一个标准的功能。

    首先我们在 EthernetManager中添加一个函数updateIface
    
       
    1. /*
    2. * up and down eth0
    3. */
    4. public void updateIface(String iface,boolean up){
    5. try {
    6. mService.updateIfaceState(iface,up);
    7. } catch (RemoteException e) {
    8. throw e.rethrowFromSystemServer();
    9. }
    10. }

    此时需要在EthernetServiceImpl中添加函数updateIfaceState

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

    Override注解说明这是重写函数,EthernetServiceImpl继承自IEthernetManager.Stub,所以我们需要在对应的IEthernetManager.aidl接口文件中加入updateIfaceState声明,如下所示:

    
       
    1. // IethernetManager.aidl
    2. interface IEthernetManager
    3. {
    4. IpConfiguration getConfiguration();
    5. void setConfiguration(in IpConfiguration config);
    6. boolean isAvailable();
    7. void addListener(in IEthernetServiceListener listener);
    8. void removeListener(in IEthernetServiceListener listener);
    9. void updateIfaceState(String iface,boolean up);
    10. }

    这里之后会调用mTracker.changeEthernetState函数在EthernetNetworkFactory创建函数changeEthernetState

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

    到此结束,从EthernetManagerEthernetNetworkFactory中关于网口开关的功能就做完了,我们只需要调用EthernetManager中的updateIface函数就能实现网口的打开与关闭功能。



    6 监听网线拔出

    之前在第四节中介绍过监听网线的插拔功能,第五节中介绍了在不拔网线的情况下打开与关闭网口,这个时候就会遇到一个问题,那就是我无法正确的监听到网线的拔出。实际操作中会发现,打开与关闭网口是,监听器监听同样会被调用,但是此时我并没有拔出网线。换一个说法就是,网口的打开与关闭实际上模拟的就是网线的插拔功能。

    那此时我就需要正确区分开网口的关闭与网线的拔出这两种情况。

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

    
       
    1. private class InterfaceObserver extends BaseNetworkObserver {
    2. @Override
    3. public void interfaceLinkStateChanged(String iface, boolean up) {
    4. updateInterfaceState(iface, up);
    5. }
    6. @Override
    7. public void interfaceAdded(String iface) {
    8. maybeTrackInterface(iface);
    9. }
    10. @Override
    11. public void interfaceRemoved(String iface) {
    12. stopTrackingInterface(iface);
    13. }
    14. }

    其中interfaceAdded表示网线的插入,interfaceRemoved表示网线的拔出。为了配合系统的原生代码结构,我们可以在EthernetManagerListener接口中添加一个新函数声明,添加后的Listener接口如下:

    
       
    1. /**
    2. * A listener interface to receive notification on changes in Ethernet.
    3. */
    4. public interface Listener {
    5. /**
    6. * Called when Ethernet port's availability is changed.
    7. * @param isAvailable {@code true} if one or more Ethernet port exists.
    8. */
    9. public void onAvailabilityChanged(boolean isAvailable);
    10. /*
    11. *Called when network wire take out
    12. */
    13. public void onEthernetIfaceRemove();
    14. }

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

    具体代码如下:
    
       
    1. private void notifyListenersRemoved(){
    2. int n = mListeners.beginBroadcast();
    3. Log.i( "SIMCOMIP", "notifyListenersRemoved state listener size : "+n);
    4. for ( int i = 0; i < n; i++) {
    5. try {
    6. mListeners.getBroadcastItem(i).onEthernetIfaceRemove();
    7. } catch (RemoteException e) {
    8. // Do nothing here.
    9. }
    10. }
    11. mListeners.finishBroadcast();
    12. }

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

    
       
    1. private class InterfaceObserver extends BaseNetworkObserver {
    2. @Override
    3. public void interfaceLinkStateChanged(String iface, boolean up) {
    4. updateInterfaceState(iface, up);
    5. }
    6. @Override
    7. public void interfaceAdded(String iface) {
    8. maybeTrackInterface(iface);
    9. }
    10. @Override
    11. public void interfaceRemoved(String iface) {
    12. stopTrackingInterface(iface);
    13. notifyListenersRemoved();
    14. }
    15. }

    7. SystsemUI同步更新

    上层的SystemUI显示图标及更新是通过NetworkControllerImpl.java文件完成,具体可以自己查看代码,这里不做解析了。

    展开全文
  • Android 7.1 增加Ethernet

    2018-05-22 10:23:00
    Android 7.0 增加Ethernet设置(DHCP与Static ip) 参考文章:http://blog.csdn.net/hclydao/article/details/50972932
  • --- a/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java @@ -47,6 +...
    --- a/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
    +++ b/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java
    @@ -47,6 +47,7 @@ import android.os.Looper;
     import android.os.RemoteCallbackList;
     import android.os.RemoteException;
     import android.os.ServiceManager;
    +import android.os.SystemProperties;
     import android.text.TextUtils;
     import android.util.Log;
     import android.content.Intent;
    @@ -94,6 +95,7 @@ class EthernetNetworkFactory {
         private static final String NETWORK_TYPE = "Ethernet";
         private static final String TAG = "EthernetNetworkFactory";
         private static final int NETWORK_SCORE = 70;
    +       private static final int NETWORK_SCORE_SHARE = 30;
         private static final boolean DBG = true;
     
         /** Tracks interface changes. Called from NetworkManagementService. */
    @@ -260,9 +262,16 @@ class EthernetNetworkFactory {
                 // 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);
    +            mFactory.setScoreFilter(up ? getNetworkScore() : -1);
             }
         }
    +       
    +       private int getNetworkScore() {
    +               if ("1".equals(SystemProperties.get("persist.tchip.iproute")))
    +                       return NETWORK_SCORE_SHARE;
    +               else
    +                       return NETWORK_SCORE;
    +       }
     
         // first disconnect, then connect
         public void reconnect(String iface) {
    @@ -429,7 +438,7 @@ class EthernetNetworkFactory {
                 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
                 mNetworkAgent.sendLinkProperties(mLinkProperties);
                 // never set the network score below 0.
    -            mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
    +            mNetworkAgent.sendNetworkScore(mLinkUp? getNetworkScore() : 0);
             }
         }
        @@ -585,7 +594,7 @@ class EthernetNetworkFactory {
                         // Create our NetworkAgent.
                         mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext,
                                 NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties,
    -                            NETWORK_SCORE) {
    +                            getNetworkScore()) {
                             public void unwanted() {
                                 synchronized(EthernetNetworkFactory.this) {
                                     if (this == mNetworkAgent) {
    
    展开全文
  • packages/apps/Settings/src/com/android/settings/ethernet/getStaticIpInfo.java public interface getStaticIpInfo { public boolean getStaticIp(String ipAddr); public boolean getStaticNetMask(String ...

    平台:RK3399
    系统:Android7.1
    不同于imx6 Android4.4网络配置单独写了个app,Android7.1的以太网配置集成到了Setting系统设置APP中。如下:
    在这里插入图片描述
    在这里插入图片描述
    不过,Ethernet 静态IP模式中,IP地址、子网掩码等默认是空,没有初始值。下面尝试添加默认值。

    涉及文件:
    packages/apps/Settings/src/com/android/settings/ethernet/EtherentStaticIpDialog.java
    packages/apps/Settings/src/com/android/settings/ethernet/EthernetSettings.java
    packages/apps/Settings/src/com/android/settings/ethernet/getStaticIpInfo.java
    packages/apps/Settings/src/com/android/settings/ethernet/PppoeDialog.java
    

    网络配置涉及的文件较少,代码量也比较少,相对好操作。

            private void updateIpSettingsInfo() {
                    Log.d("blb", "Static IP status updateIpSettingsInfo");
                    ContentResolver contentResolver = mcontext.getContentResolver();
                    String staticip = /*System.getString(contentResolver,System.ETHERNET_STATIC_IP);*/
    						mEthManager.getIpAddress();
                    if (!TextUtils.isEmpty(staticip))
    						mIpAddressView.setText(staticip);
    
                    String ipmask = /*System.getString(contentResolver,System.ETHERNET_STATIC_NETMASK);*/
    						mEthManager.getNetmask();
                    if (!TextUtils.isEmpty(ipmask))
    						ipnetmask.setText(ipmask);
    
                    String gateway = /*System.getString(contentResolver,System.ETHERNET_STATIC_GATEWAY);*/
    						mEthManager.getGateway();
                    if (!TextUtils.isEmpty(gateway))
    						mIPgateway.setText(gateway);
    
                    String dns = /*System.getString(contentResolver,System.ETHERNET_STATIC_DNS1);*/
    						mEthManager.getDns();
    				String mDns1 = nullIpInfo;
    				String mDns2 = nullIpInfo;
    				if ((dns != null) && (!dns.equals(""))){
    						String data[] = dns.split(",");
                    		mDns1 = data[0];
    						if (data.length > 1)
    								mDns2 = data[1];
    				}
                    if (!TextUtils.isEmpty(mDns1))
    						mdns1.setText(mDns1);
    				if (!TextUtils.isEmpty(mDns2))
    						mdns2.setText(mDns2);
    				/*String dns2 = System.getString(contentResolver,
    						System.ETHERNET_STATIC_DNS2);
                    if (!TextUtils.isEmpty(dns2))
                            mdns2.setText(dns2);*/
            }
    

    updateIpSettingsInfo函数中已经有了DNS配置的模板,给mDns1赋初值,调用android.net.EthernetManager类中的getDns方法获取dns,如果dns为空,setText文本框输入刚才设置的初值。如果dns不为空,使用获取的dns重新设置mDns1,再将mDns1输入到文本框。
    按照相似的方法设置IPaddress、Gateway和Netmask,修改方法如下:

    diff --git a/packages/apps/Settings/src/com/android/settings/ethernet/EtherentStaticIpDialog.java b/packages/apps/Settings/src/com/android/settings/ethernet/EtherentStaticIpDial
    og.java
    index c7f1198211..077a42486d 100644
    --- a/packages/apps/Settings/src/com/android/settings/ethernet/EtherentStaticIpDialog.java
    +++ b/packages/apps/Settings/src/com/android/settings/ethernet/EtherentStaticIpDialog.java
    @@ -63,6 +63,11 @@ class ethernet_static_ip_dialog extends AlertDialog implements TextWatcher {
            static final int BUTTON_FORGET = DialogInterface.BUTTON_NEUTRAL;
    
         private final static String nullIpInfo = "0.0.0.0";
    +       private final static String defaultIP = "192.168.0.232";
    +       private final static String defaultNetMask = "255.255.255.0";
    +       private final static String defaultGateway = "192.168.0.1";
    +       private final static String defaultDns1 = "8.8.8.8";
    +       private final static String defaultDns2 = "114.114.114.114";
    
            // private final boolean mEdit;
            private final DialogInterface.OnClickListener mListener;
    @@ -120,23 +125,38 @@ class ethernet_static_ip_dialog extends AlertDialog implements TextWatcher {
                    ContentResolver contentResolver = mcontext.getContentResolver();
                    String staticip = /*System.getString(contentResolver,System.ETHERNET_STATIC_IP);*/
                               mEthManager.getIpAddress();
    -               if (!TextUtils.isEmpty(staticip))
    -                       mIpAddressView.setText(staticip);
    +               String mIP = defaultIP;
    +               if ((staticip != null) && (!staticip.equals(""))){
    +                       String data[] = staticip.split(",");
    +                       mIP = data[0];
    +               }
    +               if (!TextUtils.isEmpty(mIP))
    +                       mIpAddressView.setText(mIP);
    
                    String ipmask = /*System.getString(contentResolver,System.ETHERNET_STATIC_NETMASK);*/
                             mEthManager.getNetmask();
    -               if (!TextUtils.isEmpty(ipmask))
    -                       ipnetmask.setText(ipmask);
    +               String mIpmask = defaultNetMask;
    +               if ((ipmask != null) && (!ipmask.equals(""))){
    +                       String data[] = ipmask.split(",");
    +                       mIpmask = data[0];
    +               }
    +               if (!TextUtils.isEmpty(mIpmask))
    +                       ipnetmask.setText(mIpmask);
    
                    String gateway = /*System.getString(contentResolver,System.ETHERNET_STATIC_GATEWAY);*/
                              mEthManager.getGateway();
    -               if (!TextUtils.isEmpty(gateway))
    -                       mIPgateway.setText(gateway);
    +               String mGateway = defaultGateway;
    +               if ((gateway != null) && (!gateway.equals(""))){
    +                       String data[] = gateway.split(",");
    +                       mGateway = data[0];
    +               }
    +               if (!TextUtils.isEmpty(mGateway))
    +                       mIPgateway.setText(mGateway);
    
                    String dns = /*System.getString(contentResolver,System.ETHERNET_STATIC_DNS1);*/
                           mEthManager.getDns();
    -        String mDns1 = nullIpInfo;
    -        String mDns2 = nullIpInfo;
    +        String mDns1 = defaultDns1;
    +        String mDns2 = defaultDns2;
             if ((dns != null) && (!dns.equals(""))){
                 String data[] = dns.split(",");
                            mDns1 = data[0];
    
    展开全文
  • 修复android7.1,4g模块和以太网同时连接后关闭移动数据,以太网不能自动起来的bug
  • 客户反馈正常机器放置一天时间,第二天来发现以太网无法上网,以太网灯还是正常闪烁的。 问题分析: 1.尝试插拔网线,网络可以恢复正常 2.从抓取到的kernel log看,以太网无异常 3.ifconfig查看以太网ip信息,...
  • 最新经常有客户问在哪里可以查看以太网的MAC地址,由于Android原生系统更多应用于手机等使用WIFI环境的手持设备,没有以太网相关信息很正常,我们在状态信息下直接加一栏以太网的MAC地址信息; 方法: 参考WLAN...
  • 源码patch RK7.1 添加以太网接口,并在设置-显示中添加以太网开关 代码patch
  • public String doEthernetShare() { String result = "Failure"; DataOutputStream dataOutputStream = null; BufferedReader errorStream = null; String networkType = g...
  • android4系统实现以太网来分享设备的internet网络(4G/wifi),framework层强制修改eth0以太网类型,实现以太网路由功能,主要修改EthernetDateTracker.java
  • OS:Android7.1 问题描述: 客户希望能够支持应用层打开\关闭有线网,且重启设备、插拔网线均能记住以上设置状态。 我们需要在不拔出网线的同时关闭上网的功能,这个时候解决方安就是将网口关闭,等到允许上网时再...
  • RK3288_Android7.1调试以太网ethernet

    千次阅读 2019-04-18 15:54:28
    1、以太网(ethernet)的调试: Rk默认已经添加了mac驱动。网卡分为两个层次:MAC+PHY 一般说来,MAC就是网络控制器,如果该驱动OK,就能直接看到ifconfig信息; PHY是物理层,负责发送和传输的底层,如果PHY发生...
  • Android7 增加双以太网eth1的支持

    千次阅读 2020-03-30 15:09:29
    --- a/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java +++ b/frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetNetworkFactory.java @@ -146,7....
  • 说明:1.android7.1系统不支持静态广播监听网络变化 2.service和broadcast简单应用 逻辑:开机运行CheckNetService服务,启动BroadcastReceiver广播接收器,NetWorkStateReceiver接收器判断接收到的网络变化并...
  • Android以太网和wifi共存并设置Wif优先级最高 - 简书在Android5.0以后网络请求的优先级,不在以devcie下的config文件配置的顺序为主,而根据网络的连接状态,等其他因素综合动态评分机制,进行判断优先级。...
  • Android 7.0 自带EthernetService,默认开机就会启动,默认ip获取方式是动态分配(DHCP),有时候公司路由器DNS设置有问题,导致无法上网(能ping通局域网,无法上外网),手动设置静态IP就派上用场了。 废话不多说...
  • 这个项目已经很老了,其实是从 Android 4.4.4 的系统 Settings 中 copy 出来的。 其实原理都是编译运行系统 ...Android 操作以太网的项目,提供了监听网线插拔和以太网开关,设置以太网静态IP、网关、子网掩码、dns等。
  • android通过adb设置以太网共享

    千次阅读 2020-03-26 15:03:46
    开发环境:android7.1.2 开发板:SC60智能模组+带网口的...2、android设备通过以太网给其它终端供网,对应设置中的便携式热点以太网共享-ethernettethering 二、实现方法 通过adb shell settings list global 来...
  • RK3288 Android7.1软件开发指南

    千次阅读 2019-05-27 15:11:51
    文档主要介绍Rockchip RK3288 Android7.1 软件开发指南,旨在帮助软件开发工程师更快上手RK3288的开发及调试。 1.1 DDR 支持列表 RK3288 支持双通道 DDR3、DDR3L、LPDDR2、LPDDR3。 RK3288 DDR 颗粒支持程度列表...
  • 7.1 4G路由功能实现

    2020-11-25 14:49:35
    实现功能:4G网络通过RJ45共享给其他设备 framework层实现: RK7.1的代码中已经集成了双以太网功能,通过: 设置属性: persist.net.ethernet.mode=multi 开启双以太网 JAVA层实现: public String ...
  • OS: Android 7.1.1 现象 机器通过交换机连接路由器,当路由器断电或者断开和交换机的连接时,机器的IP地址无法及时更新的问题. 分析 Android7.1.1使用IpReachabilityMonitor来监视链路IP的可达性,无论任何时候,一旦...
  • 蔡工RK3288_Android7.1驱动开发入门 多年Android/Li...
  • android 8.1 framework层修改以太网静态ip功能

    千次阅读 热门讨论 2019-01-25 09:47:24
    Android5.0基础上到Android7.0,Android都自带了以太网的设置功能,基本上都是将ip地址和网关之类的信息通过StaticIpConfiguration该对象实现联网功能。到了Android 8.1 如果还是照着7.0的来写,可能会出现配置了...
  • android 7.1反射调用系统接口设置静态IP地址

    千次阅读 热门讨论 2018-03-31 15:35:59
    // 设置以太网连接模式设置集合 STATIC DHCP UNASSIGNED ipAssignmentMap.put(enu.toString(), enu); } } } // 获取ipConfiguration类的构造方法 Constructor[] ipConfigConstructors = ipConfigurationClass...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 330
精华内容 132
关键字:

android7.1以太网