在前面看过Android7.0与8.0的以太网后,对9.0的以太网解决起来更得心应手了。在添加以太网后,可以顺利设置静态ip.但是当我设置静态后,出现需要将网线拔插一次更新网络后才能刷新ip地址的bug。当时以为只要像7.0和8.0那样新增就没有问题了,没想到这次9.0又改变了代码结构。下面我将详细介绍9.0的网络步骤。

以下是设计到的文件极其目录:

packages\apps\Settings\src\com\android\settings\ethernet\EthernetConfigDialog.java-----------设置静态ip,自己新增

frameworks\base\core\java\android\net\EthernetManager.java

frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl.java

frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetTracker.java ————区别其他版本,Google新增的类

frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetNetworkFactory.java

为了能够在不看其他版本或者不了解之前Android版本以太网流程情况下尽快熟知,我这里还是需要啰嗦的讲一下以太网的流程。

以下仅设置静态ip流程。

1:主动调用设置静态ip方法

try {StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();InetAddress mIpAddr = NetworkUtils.numericToInetAddress(mIpaddr.getText().toString());//ip地址String[] strs = mMask.getText().toString().split("\\.");//子网掩码参数int count = 0;for(String str : strs){if(str.equals("255")){count++;}}int prefixLength = count*8;LinkAddress mIpAddress = new LinkAddress(mIpAddr,prefixLength);InetAddress mGateway = NetworkUtils.numericToInetAddress(mGw.getText().toString());//网关地址ArrayList<InetAddress> mDnsServers = new ArrayList<InetAddress>();mDnsServers.add(NetworkUtils.numericToInetAddress(mDns1.getText().toString()));//dns1
//与dns2的值mDnsServers.add(NetworkUtils.numericToInetAddress(mDns2.getText().toString()));staticIpConfiguration.ipAddress = mIpAddress;staticIpConfiguration.gateway = mGateway;staticIpConfiguration.dnsServers.addAll(mDnsServers);config = new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, staticIpConfiguration, ProxyInfo.buildDirectProxy(null,0));mEthManager.setConfiguration("eth0",config);//此处区别//于其他Android版本修改,多了一个参数需要传端口名}catch (Exception e) {e.printStackTrace();  }

注意一点事mEthManager.setConfiguration();Android9.0版本变成两个参数了。

通过设置好静态ip地址所需要的参数后,调用EthernetManager类里面的setConfiguration方法进行参数配置。我们看一下这个方法具体做了什么操作。

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

发现又是通过mService.setConfiguration()方法。那么这个mService是哪里传来的呢,我找到了构造方法

 /*** Create a new EthernetManager instance.* Applications will almost always want to use* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve* the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.*/public EthernetManager(Context context, IEthernetManager service) {mContext = context;mService = service;}

其中IEthernetManager这个看似接口实例化的对象,我通过找到发现在

public class EthernetServiceImpl extends IEthernetManager.Stub{}类中运用到。也就是EthernetServiceImpl 继承了IEthernetManager.Stub。Android的Binder机制。

在EthernetServiceImpl 中找到方法

 /*** Set Ethernet configuration*/@Overridepublic void setConfiguration(String iface, IpConfiguration config) {if (!mStarted.get()) {Log.w(TAG, "System isn't ready enough to change ethernet configuration");}enforceConnectivityInternalPermission();if (mTracker.isRestrictedInterface(iface)) {enforceUseRestrictedNetworksPermission();}// TODO: this does not check proxy settings, gateways, etc.// Fix this by making IpConfiguration a complete representation of static configuration.mTracker.updateIpConfiguration(iface, new IpConfiguration(config));}

上面是9.0中的方法实现。从这里开始已经跟8.0之前的版本不同了。我们看一下8.0之前的版本是这个方法是怎么写的。


Android8.1中的实现方式/*** Set Ethernet configuration*/@Overridepublic 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);}}}

我们也是看着都是mTracker对象调用方法进行设置。其实这两个mTracker是不同的对象。在9.0之前的版本,这个mTracker对象都是EthernetNetworkFactory的实例对象。因为后续的设置参数进行连接网络判断端口等一系列操作都在这个EthernetNetworkFactory类中完成。而在9.0后,Google将他们抽离出来了,对于监听以太网切换、以太网判断当前网络是否可用等一些列操作抽离到一个EthernetTracker类中。那么9.0的EthernetNetworkFactory只需要关心拿到参数进行连接上网操作就可以了。

我们现在只关心9.0是怎么走的。找到EthernetTracker类的具体实现,

void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {if (DBG) {Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration);}mConfigStore.write(iface, ipConfiguration);mIpConfigurations.put(iface, ipConfiguration);mHandler.post(() -> mFactory.updateIpConfiguration(iface, ipConfiguration));}

最后是调用EthernetNetworkFactory中的方法,而其实这个方法并没有做任何上网的操作。

void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {NetworkInterfaceState network = mTrackingInterfaces.get(iface);if (network != null) {network.setIpConfig(ipConfiguration);}}

他做的操作仅仅只是将设置的ip地址等以太网参数保存下来。

说道这里我想大家已经知道了在9.0不能立马实现修改ip的问题所在了。如果我们做到这一步,已经可以通过拔插网线实现设置静态ip上网。那么接下来,我们看看正常流程怎么走。

还是继续看EthernetTracker类。因为判断能不能连接网络的条件都在这里实现。

EthernetTracker(Context context, Handler handler) {mHandler = handler;// The services we use.IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);mNMService = INetworkManagementService.Stub.asInterface(b);// Interface match regex.mIfaceMatch = context.getResources().getString(com.android.internal.R.string.config_ethernet_iface_regex);// Read default Ethernet interface configuration from resourcesfinal String[] interfaceConfigs = context.getResources().getStringArray(com.android.internal.R.array.config_ethernet_interfaces);for (String strConfig : interfaceConfigs) {parseEthernetConfig(strConfig);}mConfigStore = new EthernetConfigStore();NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */);mFactory = new EthernetNetworkFactory(handler, context, nc);mFactory.register();}void start() {mConfigStore.read();// Default interface is just the first one we want to track.mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface();final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations();for (int i = 0; i < configs.size(); i++) {mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i));}try {mNMService.registerObserver(new InterfaceObserver());} catch (RemoteException e) {Log.e(TAG, "Could not register InterfaceObserver " + e);}mHandler.post(this::trackAvailableInterfaces);}

这个start()方法,就是正常上网的第一个被调用的方法,一般我们连接网线后,这个方法就会被调用。trackAvailableInterfaces是接下来要走的方法

 private void trackAvailableInterfaces() {try {final String[] ifaces = mNMService.listInterfaces();for (String iface : ifaces) {maybeTrackInterface(iface);}} catch (RemoteException | IllegalStateException e) {Log.e(TAG, "Could not get list of interfaces " + e);}}private void maybeTrackInterface(String iface) {if (DBG) Log.i(TAG, "maybeTrackInterface " + iface);// If we don't already track this interface, and if this interface matches// our regex, start tracking it.if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface)) {return;}if (mIpConfigForDefaultInterface != null) {updateIpConfiguration(iface, mIpConfigForDefaultInterface);mIpConfigForDefaultInterface = null;}addInterface(iface);}private void addInterface(String iface) {InterfaceConfiguration config = null;// Bring up the interface so we get link status indications.try {mNMService.setInterfaceUp(iface);config = mNMService.getInterfaceConfig(iface);} catch (RemoteException | IllegalStateException e) {// Either the system is crashing or the interface has disappeared. Just ignore the// error; we haven't modified any state because we only do that if our calls succeed.Log.e(TAG, "Error upping interface " + iface, e);}if (config == null) {Log.e(TAG, "Null interface config for " + iface + ". Bailing out.");return;}final String hwAddress = config.getHardwareAddress();NetworkCapabilities nc = mNetworkCapabilities.get(iface);if (nc == null) {// Try to resolve using mac addressnc = mNetworkCapabilities.get(hwAddress);if (nc == null) {nc = createDefaultNetworkCapabilities();}}IpConfiguration ipConfiguration = mIpConfigurations.get(iface);if (ipConfiguration == null) {ipConfiguration = createDefaultIpConfiguration();}Log.d(TAG, "Started tracking interface " + iface);mFactory.addInterface(iface, hwAddress, nc, ipConfiguration);// Note: if the interface already has link (e.g., if we crashed and got// restarted while it was running), we need to fake a link up notification so we// start configuring it.if (config.hasFlag("running")) {updateInterfaceState(iface, true);}}

一些列判断成功后就通过mFactory去调用连接网络的操作了。

所以,当我们主动设置静态ip时需要在frameworks\opt\net\ethernet\java\com\android\server\ethernet\EthernetServiceImpl.java类中添加下面修改:

/*** Set Ethernet configuration*/@Overridepublic void setConfiguration(String iface, IpConfiguration config) {if (!mStarted.get()) {Log.w(TAG, "System isn't ready enough to change ethernet configuration");}enforceConnectivityInternalPermission();if (mTracker.isRestrictedInterface(iface)) {enforceUseRestrictedNetworksPermission();}// TODO: this does not check proxy settings, gateways, etc.// Fix this by making IpConfiguration a complete representation of static configuration.mTracker.updateIpConfiguration(iface, new IpConfiguration(config));mTracker.start();//重新连接网络}

我们重新调用start()方法去连接一下网络。我以为这样就可以了,如果是8.0确实好像可以。然后出现了问题。最后一步一步判断发现在EthernetTracker的方法。(请看中文注释)

private void maybeTrackInterface(String iface) {if (DBG) Log.i(TAG, "maybeTrackInterface " + iface);// If we don't already track this interface, and if this interface matches// our regex, start tracking it.//此处的判断需要注意,mFactory.hasInterface(iface)并不同于8.0以前的判断。我们具体看一下if (!iface.matches(mIfaceMatch) || mFactory.hasInterface(iface)) {return;}if (mIpConfigForDefaultInterface != null) {updateIpConfiguration(iface, mIpConfigForDefaultInterface);mIpConfigForDefaultInterface = null;}addInterface(iface);}

这个判断的方法是这样的

boolean hasInterface(String interfacName) {return mTrackingInterfaces.containsKey(interfacName);//eth0}

而这个集合是添加的端口记录的

void addInterface(String ifaceName, String hwAddress, NetworkCapabilities capabilities,IpConfiguration ipConfiguration) {if (mTrackingInterfaces.containsKey(ifaceName)) {Log.e(TAG, "Interface with name " + ifaceName + " already exists.");return;}if (DBG) {Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + capabilities);}NetworkInterfaceState iface = new NetworkInterfaceState(ifaceName, hwAddress, mHandler, mContext, capabilities);iface.setIpConfig(ipConfiguration);mTrackingInterfaces.put(ifaceName, iface);//看这里看这里看这里看这里看这里updateCapabilityFilter();}

所以,当连接网线后,如果是同一个端口已经上网了,那么集合里面已经包含了该端口名了。所以我们在重新连接的时候,需要先清空我们的端口名。

最后

/*** Set Ethernet configuration*/@Overridepublic void setConfiguration(String iface, IpConfiguration config) {if (!mStarted.get()) {Log.w(TAG, "System isn't ready enough to change ethernet configuration");}enforceConnectivityInternalPermission();if (mTracker.isRestrictedInterface(iface)) {enforceUseRestrictedNetworksPermission();}// TODO: this does not check proxy settings, gateways, etc.// Fix this by making IpConfiguration a complete representation of static configuration.mTracker.updateIpConfiguration(iface, new IpConfiguration(config));mTracker.removeInterface(iface);//清除当前端口mTracker.start();}

好了用过上面的修改,我们就可以实现9.0修改以太网静态ip地址了。希望能够有用。

今夕是何夕~

晚风过花庭~

Android 9.0 以太网上网设置静态ip,解决拔插后才能更改ip地址的问题相关推荐

  1. Android 8.0 VTS 测试 FAIL 失败项解决记录

    Android 8.0 VTS 测试 FAIL 失败项解决记录 Qidi 2017.08.09 (Markdown & Haroopad) 注意:本文基于 Android 8.0 进行分析. ...

  2. Android 8.0 的部分坑及对应解决方法

    Android 8.0 的部分坑及对应解决方法 参考文章: (1)Android 8.0 的部分坑及对应解决方法 (2)https://www.cnblogs.com/nesger/p/9483582 ...

  3. android手机连接无线路由器上网设置,手机连接无线网络怎么设置?手机Wifi无线网设置教程...

    随着智能手机无线上网的流行,如今很多家庭都会组建Wifi无线网络,目前组建Wifi网络,大致有两种情况,一种是使用无线路由器,另外一种是将笔记本变身无线无路由器,从而实现智能手机也可以免费Wifi上网 ...

  4. android 4.0 原生短信,Android 4.0 短信发不出去解决办法

    我的Nexus S 年前就刷成4.0 了,昨天因为手机流量太大,花了我100块钱,我去看了是自己的手机Exchange服务浪费了大量的流量,但是不知道是为什么,于是昨天晚上用*#4636#*#*去查看 ...

  5. android 8.0 l2tp问题,Android 8.0 的部分坑及对应解决方法

    虽然 Android 9.0 都已经面世了,本篇文章写的有点迟了. 但是迟到好过不到,因此基于此这边还是记录一下项目中遇到的 Android 8.0 的坑及对应解决方法. 每次系统升级,虽然系统功能更 ...

  6. kodi android 卡顿,给Kodi设置缓存来解决播放大文件卡顿

    给Kodi设置缓存来解决播放大文件卡顿 2021-03-02 16:21:20 28点赞 355收藏 31评论 Kodi可以算是电视盒子上最棒的播放器了,它具有强大的功能,优美的界面,相信很多人也都是 ...

  7. 软件测试工作怎样修改本机IP,如何在命令行下更改IP地址

    如何在命令行下更改IP地址 发表于:2007-07-02来源:作者:点击数: 标签: 微软的Windows家族从Windows NT开始跨入了 网络 操作系统的市场,到现在的Windows 2000可 ...

  8. android手机连接无线路由器上网设置,能连接WIFI但无法上网?教你如何为手机分配固定IP图文教程...

    前天遇到了一个奇怪的问题,手机使用家里面的wif无线网络上网,能连接WIFI无线网络,也能够显示连接成功的信息,在手机的通知栏里面同时也显示了wif连接成功的图标,可怎么就上不了网.不论是登腾讯QQ还 ...

  9. VMware下redhat9.0的上网设置

    在安装好VMware,redhat后可以看到VMware的Edit菜单的Virtual Network Editor,可以看到NAT方式的是虚拟路由8,所以我们就只要关注VMnet8就好了,然后选择H ...

最新文章

  1. php PDO 浮点数返回,php – 如何在PDO中简单地返回对象?
  2. 练习:卷积和池化过程中注意事项
  3. 汇编语言的准备知识--给初次接触汇编者 (1-4) 转载
  4. 【NOIP2018】赛道修建【二分】【树形dp】【multiset】【贪心】
  5. gradle compile mysql_Gradle配置implementation、api与compile的区别
  6. 强化学习q学习求最值_Q学习简介:强化学习
  7. 互动中国分享: 15例HTML5酷站欣赏
  8. python的datetime模块用法_Python3.5内置模块之time与datetime模块用法实例分析
  9. 关闭Windows 10系统更新以及查看电脑机型
  10. [JOYOI] 自然数拆分Lunatic版
  11. mysql 无限上级_mysql无限上级
  12. java将数字转为大写(1转为一)
  13. Installing VMware Tools, please wait解决办法
  14. ecshop4.0php,ECSHOP安装教程【ECSHOP4.0安装教程】图解ECSHOP4.0安装教程流程和步骤-ECSHOP教程网...
  15. Vue Resource
  16. 为马来西亚航空失联飞机祈福~~
  17. System.Runtime.InteropServices.InvalidComObjectException:“COM 对象与其基础 RCW 分开后就不能再使用。”报错解决
  18. Pion流媒体服务测试
  19. cad把图形切成两部分_转载一位CAD大神的学习笔记, 初学CAD的人可以看看
  20. 电脑使用技巧(Win10修改窗口背景颜色)

热门文章

  1. rubymine性能调优
  2. C#理解InitializeComponent()方法
  3. 如果打开一个网页加载很慢,该如何定位问题
  4. 三个整数和与积中位数c语言,湖北省宜昌市枝江市届中考数学3月模拟试卷.pdf
  5. 程序地址空间:虚拟地址原理及发展过程(图解说明)
  6. 2.1、MySQL Workbench 使用
  7. Android-布局管理器
  8. AI 绘画Stable Diffusion 研究(五)sd文生图功能详解(下)
  9. 如何使用CMD操纵MySQL数据库?
  10. 工程项目如何科学管理项目进度