javaee论坛

普通会员

225648

帖子

334

回复

348

积分

楼主
发表于 2019-10-31 15:03:24 | 查看: 1409 | 回复: 1

朋友们,最近又开始搞AndroidP了,同样的以太网静态IP是少不了的功能,今天我们就开始来整一下。之前弄6.0和8.1的都ok了。

没想到9.0改动还是略微有点大的。来来来,先看图。

效果图

上代码app层

Settings中的代码和之前的一样就不贴了,可以去看之前的这篇中代码Android8.1MTK平台增加以太网静态IP功能

或者下载这篇的源码资源

framework层

驱动大哥已经把驱动都搞定了,现在直接插上网线,设备就能上网,网卡图标也正常显示。我们需要控制网卡的开关,先来简单看下流程。

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

publicfinalclassEthernetServiceextendsSystemService{privatestaticfinalStringTAG="EthernetService";finalEthernetServiceImplmImpl;publicEthernetService(Contextcontext){super(context);mImpl=newEthernetServiceImpl(context);}@OverridepublicvoidonStart(){Log.i(TAG,"Registeringservice"+Context.ETHERNET_SERVICE);publishBinderService(Context.ETHERNET_SERVICE,mImpl);}@OverridepublicvoidonBootPhase(intphase){if(phase==SystemService.PHASE_SYSTEM_SERVICES_READY){mImpl.start();}}}

EthernetService继承了系统服务,那自然也就是系统服务,如果挂掉会自动重新创建,严重情况会导致系统重启,我就试出来过。看下当PHASE_SYSTEM_SERVICES_READY准备完成,调用EthernetServiceImpl的start()

来看下这个start()都干了啥

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

publicvoidstart(){Log.i(TAG,"StartingEthernetservice");HandlerThreadhandlerThread=newHandlerThread("EthernetServiceThread");handlerThread.start();mHandler=newHandler(handlerThread.getLooper());mTracker=newEthernetTracker(mContext,mHandler);mTracker.start();mStarted.set(true);}

主要创建了EthernetTracker,这个类是9.0中新增出来的,用于监听以太网的切换、以太网判断当前网络是否可用等一系列操作。之前8.1中都集成在EthernetNetworkFactory中,继续跟进

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

voidstart(){mConfigStore.read();//Defaultinterfaceisjustthefirstonewewanttotrack.mIpConfigForDefaultInterface=mConfigStore.getIpConfigurationForDefaultInterface();finalArrayMap<String,IpConfiguration>configs=mConfigStore.getIpConfigurations();Log.e(TAG,"mIpConfigForDefaultInterface=="+mIpConfigForDefaultInterface);Log.i(TAG,"IpConfigurationsize=="+configs.size());for(inti=0;i<configs.size();i++){mIpConfigurations.put(configs.keyAt(i),configs.valueAt(i));}try{mNMService.registerObserver(newInterfaceObserver());}catch(RemoteExceptione){Log.e(TAG,"CouldnotregisterInterfaceObserver"+e);}mHandler.post(this::trackAvailableInterfaces);}

mConfigStore对象用来管理保存的IpConfigStore信息,EthernetConfigStore中通过读取/misc/ethernet/ipconfig.txt中保存的信息进行维护一个ArrayMap<String,IpConfiguration>,根据打印的日志看,start()中每次获取到的size都为0,基本上没起作用。值得一提的是,在EthernetTracker的构造方法中通过解析config_ethernet_interfaces字符串也可向map中添加初始信息。

EthernetTracker(Contextcontext,Handlerhandler){mHandler=handler;//Theservicesweuse.IBinderb=ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);mNMService=INetworkManagementService.Stub.asInterface(b);//Interfacematchregex.mIfaceMatch=context.getResources().getString(com.android.internal.R.string.config_ethernet_iface_regex);//ReaddefaultEthernetinterfaceconfigurationfromresourcesfinalString[]interfaceConfigs=context.getResources().getStringArray(com.android.internal.R.array.config_ethernet_interfaces);for(StringstrConfig:interfaceConfigs){parseEthernetConfig(strConfig);}mConfigStore=newEthernetConfigStore();NetworkCapabilitiesnc=createNetworkCapabilities(true/*cleardefaultcapabilities*/);mFactory=newEthernetNetworkFactory(handler,context,nc);mFactory.register();}privatevoidparseEthernetConfig(StringconfigString){String[]tokens=configString.split(";");Stringname=tokens[0];Stringcapabilities=tokens.length>1?tokens[1]:null;NetworkCapabilitiesnc=createNetworkCapabilities(!TextUtils.isEmpty(capabilities)/*cleardefaultcapabilities*/,capabilities);mNetworkCapabilities.put(name,nc);if(tokens.length>2&&!TextUtils.isEmpty(tokens[2])){IpConfigurationipConfig=parseStaticIpConfiguration(tokens[2]);mIpConfigurations.put(name,ipConfig);}}

config_ethernet_interfaces的初始值位置在

frameworks\base\core\res\res\values\config.xml

<!--Regexofwiredethernetifaces--><stringtranslatable="false"name="config_ethernet_iface_regex">eth\\d</string><!--ConfigurationofEthernetinterfacesinthefollowingformat:<interfacename|macaddress>;[NetworkCapabilities];[IPconfig]Where[NetworkCapabilities]Optional.Acommasepratedlistofnetworkcapabilities.ValuesmustbefromNetworkCapabilities#NET_CAPABILITIES_*constants.[IPconfig]Optional.Ifemptyornotspecified-DHCPwillbeused,otherwiseusethefollowingformattospecifystaticIPconfiguration:ip=<ip-address/mask>gateway=<ip-address>dns=<comma-sep-ip-addresses>domains=<comma-sep-domains>--><string-arraytranslatable="false"name="config_ethernet_interfaces"><!--<item>eth1;12,13,14,15;ip=192.168.0.10/24gateway=192.168.0.1dns=4.4.4.4,8.8.8.8</item><item>eth2;;ip=192.168.0.11/24</item>--></string-array>

好了继续回到刚刚的start()中,接下来应该调用trackAvailableInterfaces(),来看下完整的流程,maybeTrackInterface中先进行iface判断,这个指代要使用的网口名称,通过命令ifconfig-a可以看到你设备下的所有网口名称。

mIfaceMatch对应刚刚的config.xml中配置的eth\d,所以只有是eth打头并且mFactory中不存在的才能设置以太网连接,这很关键

继续调用addInterface(),将iface对应的ipConfiguration通过mFactoryaddInterface,再然后updateInterfaceState广播通知当前以太网连接状态CONNECTED/CONNECTED

privatevoidtrackAvailableInterfaces(){try{finalString[]ifaces=mNMService.listInterfaces();for(Stringiface:ifaces){maybeTrackInterface(iface);}}catch(RemoteException|IllegalStateExceptione){Log.e(TAG,"Couldnotgetlistofinterfaces"+e);}}privatevoidmaybeTrackInterface(Stringiface){if(DBG)Log.i(TAG,"maybeTrackInterface"+iface);//Ifwedon'talreadytrackthisinterface,andifthisinterfacematches//ourregex,starttrackingit.if(!iface.matches(mIfaceMatch)||mFactory.hasInterface(iface)){Log.d(TAG,iface+"return");return;}Log.e(TAG,"maybeTrackInterface"+iface);if(mIpConfigForDefaultInterface!=null){updateIpConfiguration(iface,mIpConfigForDefaultInterface);mIpConfigForDefaultInterface=null;}addInterface(iface);}privatevoidaddInterface(Stringiface){InterfaceConfigurationconfig=null;//Bringuptheinterfacesowegetlinkstatusindications.try{mNMService.setInterfaceUp(iface);config=mNMService.getInterfaceConfig(iface);}catch(RemoteException|IllegalStateExceptione){//Eitherthesystemiscrashingortheinterfacehasdisappeared.Justignorethe//error;wehaven'tmodifiedanystatebecauseweonlydothatifourcallssucceed.Log.e(TAG,"Erroruppinginterface"+iface,e);}if(config==null){Log.e(TAG,"Nullinterfaceconfigfor"+iface+".Bailingout.");return;}finalStringhwAddress=config.getHardwareAddress();NetworkCapabilitiesnc=mNetworkCapabilities.get(iface);if(nc==null){//Trytoresolveusingmacaddressnc=mNetworkCapabilities.get(hwAddress);if(nc==null){nc=createDefaultNetworkCapabilities();}}IpConfigurationipConfiguration=mIpConfigurations.get(iface);if(ipConfiguration==null){ipConfiguration=createDefaultIpConfiguration();}Log.d(TAG,"Startedtrackinginterface"+iface);mFactory.addInterface(iface,hwAddress,nc,ipConfiguration);//Note:iftheinterfacealreadyhaslink(e.g.,ifwecrashedandgot//restartedwhileitwasrunning),weneedtofakealinkupnotificationsowe//startconfiguringit.if(config.hasFlag("running")){updateInterfaceState(iface,true);}}privatevoidupdateInterfaceState(Stringiface,booleanup){Log.e(TAG,"updateInterfaceStateup=="+up);booleanmodified=mFactory.updateInterfaceLinkState(iface,up);if(modified){booleanrestricted=isRestrictedInterface(iface);intn=mListeners.beginBroadcast();for(inti=0;i<n;i++){try{if(restricted){ListenerInfolistenerInfo=(ListenerInfo)mListeners.getBroadcastCookie(i);if(!listenerInfo.canUseRestrictedNetworks){continue;}}mListeners.getBroadcastItem(i).onAvailabilityChanged(iface,up);}catch(RemoteExceptione){//Donothinghere.}}mListeners.finishBroadcast();}}

知道了EthernetTracker的start()去连接以太网,那么我们在EthernetServiceImpl中增加布尔判断就能控制以太网开关状态。

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

publicclassEthernetServiceImplextendsIEthernetManager.Stub{privatestaticfinalStringTAG="EthernetServiceImpl";publicstaticfinalStringIS_ETHERNET_OPEN=Settings.IS_ETHERNET_OPEN;publicstaticfinalStringETHERNET_USE_STATIC_IP=Settings.IS_ETHERNET_STATUC_OPEN;privatefinalContextmContext;privatefinalAtomicBooleanmStarted=newAtomicBoolean(false);privateIpConfigurationmIpConfiguration;privatefinalEthernetOpenedObservermOpenObserver=newEthernetOpenedObserver();privatefinalEthernetStaticObservermStaticObserver=newEthernetStaticObserver();privateHandlermHandler;privateEthernetTrackermTracker;publicEthernetServiceImpl(Contextcontext){mContext=context;Log.i(TAG,"CreatingEthernetConfigStore");mContext.getContentResolver().registerContentObserver(System.getUriFor(IS_ETHERNET_OPEN),false,mOpenObserver);mContext.getContentResolver().registerContentObserver(System.getUriFor(ETHERNET_USE_STATIC_IP),false,mStaticObserver);}....publicvoidstart(){Log.i(TAG,"StartingEthernetservice");HandlerThreadhandlerThread=newHandlerThread("EthernetServiceThread");handlerThread.start();mHandler=newHandler(handlerThread.getLooper());mTracker=newEthernetTracker(mContext,mHandler);mIpConfiguration=mTracker.getDefaultIpConfiguration();if(getState()==1){if(isStatic()){StaticIpConfigurationstaticIpConfiguration=newStaticIpConfiguration();staticIpConfiguration.domains=Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_NETMASK);try{staticIpConfiguration.gateway=InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_GATEWAY));staticIpConfiguration.ipAddress=newLinkAddress(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_IP)),24);staticIpConfiguration.dnsServers.add(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_DNS1)));staticIpConfiguration.dnsServers.add(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_DNS2)));}catch(Exceptione){e.printStackTrace();}mIpConfiguration.ipAssignment=IpAssignment.STATIC;mIpConfiguration.proxySettings=ProxySettings.STATIC;mIpConfiguration.staticIpConfiguration=staticIpConfiguration;}mTracker.start();mStarted.set(true);}}privatebooleanisStatic(){Log.e(TAG,"EthernetServiceImplisStatic()"+Settings.System.getInt(mContext.getContentResolver(),ETHERNET_USE_STATIC_IP,0));returnSettings.System.getInt(mContext.getContentResolver(),ETHERNET_USE_STATIC_IP,0)==1;}privateintgetState(){intstate=Settings.System.getInt(mContext.getContentResolver(),IS_ETHERNET_OPEN,0);Log.e(TAG,"EthernetServiceImplgetState()"+state);returnstate;}....@OverridepublicvoidsetConfiguration(Stringiface,IpConfigurationconfig){if(!mStarted.get()){Log.w(TAG,"Systemisn'treadyenoughtochangeethernetconfiguration");}enforceConnectivityInternalPermission();if(mTracker.isRestrictedInterface(iface)){enforceUseRestrictedNetworksPermission();}Log.e(TAG,"setConfigurationiface="+iface);//TODO:thisdoesnotcheckproxysettings,gateways,etc.//FixthisbymakingIpConfigurationacompleterepresentationofstaticconfiguration.mTracker.updateIpConfiguration(iface,newIpConfiguration(config));//addmTracker.removeInterface(iface);mTracker.start();}....privatefinalclassEthernetOpenedObserverextendsContentObserver{publicEthernetOpenedObserver(){super(newHandler());}@OverridepublicvoidonChange(booleanselfChange,Uriuri,intuserId){super.onChange(selfChange,uri,userId);Log.i(TAG,"EthernetServiceImplisEthernetOpenonChange....");if(getState()==1){if(isStatic()){StaticIpConfigurationstaticIpConfiguration=newStaticIpConfiguration();staticIpConfiguration.domains=Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_NETMASK);try{staticIpConfiguration.gateway=InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_GATEWAY));staticIpConfiguration.ipAddress=newLinkAddress(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_IP)),24);staticIpConfiguration.dnsServers.add(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_DNS1)));staticIpConfiguration.dnsServers.add(InetAddress.getByName(Settings.System.getString(mContext.getContentResolver(),Settings.ETHERNET_STATIC_DNS2)));}catch(Exceptione){e.printStackTrace();}mIpConfiguration.ipAssignment=IpAssignment.STATIC;mIpConfiguration.proxySettings=ProxySettings.STATIC;mIpConfiguration.staticIpConfiguration=staticIpConfiguration;}mTracker.start();mStarted.set(true);}else{mTracker.stop();}}}privatefinalclassEthernetStaticObserverextendsContentObserver{publicEthernetStaticObserver(){super(newHandler());}@OverridepublicvoidonChange(booleanselfChange,Uriuri,intuserId){super.onChange(selfChange,uri,userId);Log.i(TAG,"EthernetServiceImplisEthernetStaticOpenonChange....");if(!isStatic()){Log.e(TAG,"nostaticstopandstart");mTracker.recoverDHCPIpConfiguration();mTracker.stop();mTracker.start();mStarted.set(true);}}}

根据settings中设置的值IS_ETHERNET_OPEN和ETHERNET_USE_STATIC_IP判断是否加载,在EthernetTracker中新增如下几个方法

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

//关闭网卡,先更新状态为false,再从mFactory中移除eth0,不然关闭后无法再次打开,因为上面提到的判断publicvoidstop(){Log.d(TAG,"EthernetTrackerstopethernet...");updateInterfaceState("eth0",false);android.os.SystemClock.sleep(200);removeInterface("eth0");}//获取默认的IpConfiguration,如果不存在则新建一个DHCP类型的,根据实际情况修改ipAssignment和proxySettingspublicIpConfigurationgetDefaultIpConfiguration(){IpConfigurationipConfiguration=mIpConfigurations.get("eth0");returnipConfiguration!=null?ipConfiguration:newIpConfiguration(IpAssignment.DHCP,ProxySettings.NONE,null,null);}//从静态IP切换publicvoidrecoverDHCPIpConfiguration(){mIpConfigurations.put("eth0",newIpConfiguration(IpAssignment.DHCP,ProxySettings.NONE,null,null));}

测试发现频繁点击静态IP开关时,出现了数组角标越界的情况,应该是add和removeiface导致的,直接将打印try一下就可以

2019-10-2117:01:38.6751075-1285/?E/AndroidRuntime:***FATALEXCEPTIONINSYSTEMPROCESS:EthernetServiceThreadjava.lang.ArrayIndexOutOfBoundsException:length=2;index=-1atcom.android.internal.util.StateMachine$SmHandler.getCurrentState(StateMachine.java:1151)atcom.android.internal.util.StateMachine$SmHandler.access$1300(StateMachine.java:681)atcom.android.internal.util.StateMachine.toString(StateMachine.java:2088)atjava.lang.String.valueOf(String.java:2896)atjava.lang.StringBuilder.append(StringBuilder.java:132)atcom.android.server.ethernet.EthernetNetworkFactory$NetworkInterfaceState.toString(EthernetNetworkFactory.java:422)atjava.lang.String.valueOf(String.java:2896)atjava.lang.StringBuilder.append(StringBuilder.java:132)atcom.android.server.ethernet.EthernetNetworkFactory.networkForRequest(EthernetNetworkFactory.java:213)atcom.android.server.ethernet.EthernetNetworkFactory.acceptRequest(EthernetNetworkFactory.java:78)atandroid.net.NetworkFactory.evalRequest(NetworkFactory.java:234)atandroid.net.NetworkFactory.evalRequests(NetworkFactory.java:253)atandroid.net.NetworkFactory.handleSetFilter(NetworkFactory.java:204)atandroid.net.NetworkFactory.handleMessage(NetworkFactory.java:149)atandroid.os.Handler.dispatchMessage(Handler.java:106)atandroid.os.Looper.loop(Looper.java:193)atandroid.os.HandlerThread.run(HandlerThread.java:65)

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

@OverridepublicStringtoString(){try{returngetClass().getSimpleName()+"{"+"iface:"+name+","+"up:"+mLinkUp+","+"hwAddress:"+mHwAddress+","+"networkInfo:"+mNetworkInfo+","+"networkAgent:"+mNetworkAgent+","+"ipClient:"+mIpClient+","+"linkProperties:"+mLinkProperties+"}";}catch(Exceptione){e.printStackTrace();returngetClass().getSimpleName()+"{}";}}

这样就能实现开头的动图效果了

修改文件源码下载

android9.0添加Ethernet功能(settings+framework).zip


普通会员

0

帖子

326

回复

344

积分
沙发
发表于 2024-03-19 21:11:22

爱你呦

您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017