Android P 9.0 增加以太网静态IP功能

效果图

 一、Settings添加以太网的配置:

1、vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\network_and_internet.xml

<com.android.settingslib.RestrictedPreferenceandroid:key="ethernet_settings"android:title="@string/ethernet_settings_title"android:summary="@string/summary_placeholder"android:icon="@drawable/ic_ethernet_cell"android:fragment="com.android.settings.ethernet.EthernetSettings"android:order="-17"/>

在 mobile_network_settings 和 tether_settings 之间增加如上代码,

对应的 icon 资源文件是我从 SystemUI 中拷贝过来的,稍微调整了下大小,也贴给你们吧

2、vendor\mediatek\proprietary\packages\apps\MtkSettings\res\drawable\ic_ethernet_cell.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:autoMirrored="true"android:width="24dp"android:height="24dp"android:viewportWidth="48"android:viewportHeight="48"android:tint="?android:attr/colorControlNormal"><pathandroid:fillColor="#fff"android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
</vector>

vendor\mediatek\proprietary\packages\apps\MtkSettings\res\values\strings.xml

<string name="ethernet_ip_settings_invalid_ip">"Please fill in the correct format."</string>
<string name="eth_ip_settings_please_complete_settings">"Network information is not complete, please fill in the complete"</string>
<string name="save_satic_ethernet">"Save"</string>
<string name="enthernet_static">"Use static settings"</string>
<string name="enthernet_ip_address">"IP address"</string>
<string name="enthernet_gateway">"gateway"</string>
<string name="enthernet_netmask">"Subnet mask"</string>
<string name="enthernet_dns1">"domain1"</string>
<string name="enthernet_dns2">"domain2"</string>
<string name="ethernet_quick_toggle_title">"Ethernet"</string>
<string name="open_ethernet">"Open Ethernet"</string>
<string name="ethernet_static_ip_settings_title">"Setting Ethernet"</string>
<string name="ethernet_settings">"Ethernet"</string>
<string name="ethernet_settings_title">"Ethernet"</string>

vendor\mediatek\proprietary\packages\apps\MtkSettings\res\values-zh-rCN\strings.xml

<string name="ethernet_ip_settings_invalid_ip">"请填写正确的格式"</string>
<string name="save_satic_ethernet">"保存"</string>
<string name="eth_ip_settings_please_complete_settings">"网络信息不完整,请填写完整"</string>
<string name="enthernet_static">"使用静态设置"</string>
<string name="enthernet_ip_address">"IP地址"</string>
<string name="enthernet_gateway">"网关"</string>
<string name="enthernet_netmask">"子网掩码"</string>
<string name="enthernet_dns1">"域名1"</string>
<string name="enthernet_dns2">"域名2"</string>
<string name="ethernet_quick_toggle_title">"以太网"</string>
<string name="open_ethernet">"打开以太网"</string>
<string name="ethernet_static_ip_settings_title">"配置以太网"</string>
<string name="ethernet_settings">"以太网"</string>
<string name="ethernet_settings_title">"以太网"</string> 

3、增加对应设置的两个布局xml

vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\ethernet_settings.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"android:title="@string/ethernet_settings"><SwitchPreferenceandroid:key="ethernet"android:title="@string/ethernet_quick_toggle_title"android:summary="@string/open_ethernet"/><PreferenceScreenandroid:dependency="ethernet"android:fragment="com.android.settings.ethernet.EthernetStaticIP"android:key="ethernet_static_ip"android:title="@string/ethernet_static_ip_settings_title" /></PreferenceScreen>

vendor\mediatek\proprietary\packages\apps\MtkSettings\res\xml\ethernet_static_ip.xml

	<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"android:title="@string/ethernet_static_ip_settings_title"><SwitchPreferenceandroid:key="use_static_ip"android:title="@string/enthernet_static"android:persistent="false"/>    <EditTextPreferenceandroid:dependency="use_static_ip"android:key="ip_address"android:title="@string/enthernet_ip_address"android:persistent="false"android:singleLine="true"/>    <EditTextPreferenceandroid:dependency="use_static_ip"android:key="gateway"android:title="@string/enthernet_gateway"android:persistent="false"android:singleLine="true"/>    <EditTextPreferenceandroid:dependency="use_static_ip"android:key="netmask"android:title="@string/enthernet_netmask"android:persistent="false"android:singleLine="true" />    <EditTextPreferenceandroid:dependency="use_static_ip"android:key="dns1"android:title="@string/enthernet_dns1"android:persistent="false"android:singleLine="true"/>    <EditTextPreferenceandroid:dependency="use_static_ip"android:key="dns2"android:title="@string/enthernet_dns2"android:persistent="false"android:singleLine="true"/>    </PreferenceScreen>

4、增加对应两个布局的 java 控制类

vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\ethernet\EthernetSettings.java

package com.android.settings.ethernet;import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v14.preference.SwitchPreference;
import android.provider.Settings;
import android.provider.Settings.System;
import android.provider.Settings.Secure;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import android.widget.Toast;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.net.InetAddress;import android.net.EthernetManager;
import android.net.StaticIpConfiguration;
import android.net.LinkAddress;
import android.net.IpConfiguration;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.R;public class EthernetSettings extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener{private static final String TAG = "EthernetSettings";private static final String USE_ETHERNET_SETTINGS = "ethernet";public static final String IS_ETHERNET_OPEN = Settings.IS_ETHERNET_OPEN;	private SwitchPreference mUseEthernet;private IntentFilter mIntentFilter;private boolean isEthernetEnabled() {return Settings.System.getInt(getActivity().getContentResolver(), IS_ETHERNET_OPEN,0) == 1 ? true : false;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);addPreferencesFromResource(R.xml.ethernet_settings);mUseEthernet = (SwitchPreference) findPreference(USE_ETHERNET_SETTINGS);mUseEthernet.setOnPreferenceChangeListener(this);if(isEthernetEnabled()) {mUseEthernet.setChecked(true);} else {mUseEthernet.setChecked(false);}File f = new File("sys/class/net/eth0/address");if (f.exists()) {mUseEthernet.setEnabled(true);		} else {mUseEthernet.setEnabled(false);}}@Overridepublic void onResume() {super.onResume();}@Overridepublic int getMetricsCategory(){return MetricsEvent.ETHERNET;}@Overridepublic void onPause() {super.onPause();}	@Overridepublic boolean onPreferenceChange(Preference preference, Object value) {boolean result = true;final String key = preference.getKey();if (USE_ETHERNET_SETTINGS.equals(key)) {Settings.System.putInt(getActivity().getContentResolver(), IS_ETHERNET_OPEN, ((Boolean) value) ? 1 : 0);}return result;}}

vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\ethernet\EthernetStaticIP.java

	package com.android.settings.ethernet;import android.app.Dialog;import android.content.DialogInterface;import android.content.Intent;import android.content.ContentResolver;import android.os.Bundle;import android.support.v7.preference.Preference;import android.preference.PreferenceActivity;import android.support.v7.preference.PreferenceScreen;import android.support.v7.preference.CheckBoxPreference;import android.support.v7.preference.EditTextPreference;import android.support.v14.preference.SwitchPreference;import android.provider.Settings;import android.provider.Settings.Secure;import android.util.Log;import android.view.ContextMenu;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.ContextMenu.ContextMenuInfo;import android.widget.AdapterView;import android.widget.Toast;import android.widget.AdapterView.AdapterContextMenuInfo;import android.text.TextUtils;import java.util.Set;import java.util.WeakHashMap;import java.util.Formatter;import java.net.InetAddress;import android.net.EthernetManager;import android.net.StaticIpConfiguration;import android.net.LinkAddress;import android.net.IpConfiguration;import android.net.IpConfiguration.IpAssignment;import android.net.IpConfiguration.ProxySettings;import android.net.NetworkInfo.DetailedState;import android.content.BroadcastReceiver;import android.content.IntentFilter;import android.content.Context;import android.net.NetworkInfo;import android.view.KeyEvent;import android.view.Menu;import android.view.MenuItem;import android.app.AlertDialog;import com.android.settings.SettingsPreferenceFragment;import com.android.settings.R;import com.android.internal.logging.nano.MetricsProto.MetricsEvent;public class EthernetStaticIP  extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener {private static final String TAG = "EthernetStaticIP";public static final boolean DEBUG = false;private static void LOG(String msg) {if ( DEBUG ) {Log.d(TAG, msg);}}/*-------------------------------------------------------*/private static final String KEY_USE_STATIC_IP = "use_static_ip";private static final String KEY_IP_ADDRESS = "ip_address";private static final String KEY_GATEWAY = "gateway";private static final String KEY_NETMASK = "netmask";private static final String KEY_DNS1 = "dns1";private static final String KEY_DNS2 = "dns2";public static final String ETHERNET_USE_STATIC_IP = Settings.IS_ETHERNET_STATUC_OPEN;private static final int MENU_ITEM_SAVE = Menu.FIRST;private static final int MENU_ITEM_CANCEL = Menu.FIRST + 1;private String[] mSettingNames = {Settings.ETHERNET_STATIC_IP, Settings.ETHERNET_STATIC_GATEWAY,Settings.ETHERNET_STATIC_NETMASK,Settings.ETHERNET_STATIC_DNS1, Settings.ETHERNET_STATIC_DNS2};private String[] mPreferenceKeys = {KEY_IP_ADDRESS,KEY_GATEWAY,KEY_NETMASK,KEY_DNS1,KEY_DNS2,};/*-------------------------------------------------------*/private SwitchPreference mUseStaticIpSwitch;private StaticIpConfiguration mStaticIpConfiguration;private IpConfiguration mIpConfiguration;private EthernetManager mEthernetManager;private boolean isOnPause = false;private boolean chageState = false;public EthernetStaticIP() {}@Overridepublic void onActivityCreated(Bundle savedInstanceState){super.onActivityCreated(savedInstanceState);addPreferencesFromResource(R.xml.ethernet_static_ip);mUseStaticIpSwitch = (SwitchPreference)findPreference(KEY_USE_STATIC_IP);mUseStaticIpSwitch.setOnPreferenceChangeListener(this);for ( int i = 0; i < mPreferenceKeys.length; i++ ) {Preference preference = findPreference(mPreferenceKeys[i] );preference.setOnPreferenceChangeListener(this);}setHasOptionsMenu(true);}@Overridepublic void onResume() {super.onResume();if(!isOnPause) {updateIpSettingsInfo();}isOnPause = false;}@Overridepublic int getMetricsCategory(){return MetricsEvent.ETHERNET_STATIC;}    @Overridepublic void onPause() {isOnPause = true;super.onPause();}@Overridepublic void onDestroy() {super.onDestroy();}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);}@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {menu.add(Menu.NONE, MENU_ITEM_SAVE, 0, R.string.save_satic_ethernet).setEnabled(true).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);super.onCreateOptionsMenu(menu, inflater);}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case MENU_ITEM_SAVE:saveIpSettingsInfo();if(isIpDataInUiComplete())finish();return true;case MENU_ITEM_CANCEL:finish();return true;}return super.onOptionsItemSelected(item);}        private void updateIpSettingsInfo() {LOG("Static IP status updateIpSettingsInfo");ContentResolver contentResolver = getContentResolver();mUseStaticIpSwitch.setChecked(Settings.System.getInt(contentResolver, ETHERNET_USE_STATIC_IP, 0) != 0);for (int i = 0; i < mSettingNames.length; i++) {EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);String settingValue = Settings.System.getString(contentResolver, mSettingNames[i]);preference.setText(settingValue);preference.setSummary(settingValue);}}private void saveIpSettingsInfo() {ContentResolver contentResolver = getContentResolver();/*      if(!chageState)   return;*/      if(!isIpDataInUiComplete()) {     Toast.makeText(getActivity(), R.string.eth_ip_settings_please_complete_settings, Toast.LENGTH_LONG).show();return;}mIpConfiguration = new IpConfiguration();mStaticIpConfiguration = new StaticIpConfiguration();for (int i = 0; i < mSettingNames.length; i++) {EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);String text = preference.getText();try {switch (mPreferenceKeys[i]) {case KEY_IP_ADDRESS:mStaticIpConfiguration.ipAddress = new LinkAddress(InetAddress.getByName(text), 24);break;case KEY_GATEWAY:mStaticIpConfiguration.gateway = InetAddress.getByName(text);break;case KEY_NETMASK:mStaticIpConfiguration.domains = text;break;case KEY_DNS1:mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(text));break;case KEY_DNS2:mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(text));break;	}            } catch (Exception e) {e.printStackTrace();}if ( null == text || TextUtils.isEmpty(text) ) {Settings.System.putString(contentResolver, mSettingNames[i], null);}else {Settings.System.putString(contentResolver, mSettingNames[i], text);}}mIpConfiguration.ipAssignment = IpAssignment.STATIC;mIpConfiguration.proxySettings = ProxySettings.STATIC;mIpConfiguration.staticIpConfiguration = mStaticIpConfiguration;	mEthernetManager = (EthernetManager) getSystemService(Context.ETHERNET_SERVICE);if (mUseStaticIpSwitch.isChecked())mEthernetManager.setConfiguration(mIpConfiguration); Settings.System.putInt(contentResolver,ETHERNET_USE_STATIC_IP, mUseStaticIpSwitch.isChecked() ? 1 : 0);// disable ethernetboolean enable = Secure.getInt(getContentResolver(), "isEnthernetOn", 1) == 1;LOG("notify Secure.ETHERNET_ON changed. enable = " + enable);if(enable) {LOG("first disable");Secure.putInt(getContentResolver(), "isEnthernetOn", 0);try {Thread.sleep(500);} catch (InterruptedException e) {}   LOG("second enable");Secure.putInt(getContentResolver(), "isEnthernetOn", 1);    	}}@Overridepublic boolean onPreferenceTreeClick(Preference preference) {boolean result = true;     LOG("onPreferenceTreeClick()  chageState = " + chageState);chageState = true;return result;}@Overridepublic boolean onPreferenceChange(Preference preference, Object newValue) {boolean result = true;String key = preference.getKey();LOG("onPreferenceChange() : key = " + key);if ( null == key ) {return true;}else if (key.equals(KEY_USE_STATIC_IP)) {}else if ( key.equals(KEY_IP_ADDRESS) || key.equals(KEY_GATEWAY)|| key.equals(KEY_NETMASK)|| key.equals(KEY_DNS1)|| key.equals(KEY_DNS2) ) { String value = (String) newValue;       LOG("onPreferenceChange() : value = " + value);if ( TextUtils.isEmpty(value) ) {( (EditTextPreference)preference).setText(value);preference.setSummary(value);result = true;}else  if ( !isValidIpAddress(value) ) {LOG("onPreferenceChange() : IP address user inputed is INVALID." );Toast.makeText(getActivity(), R.string.ethernet_ip_settings_invalid_ip, Toast.LENGTH_LONG).show();return false;}else {( (EditTextPreference)preference).setText(value);preference.setSummary(value);result = true;}}return result;}    private boolean isValidIpAddress(String value) {int start = 0;int end = value.indexOf('.');int numBlocks = 0;while (start < value.length()) {if ( -1 == end ) {end = value.length();}try {int block = Integer.parseInt(value.substring(start, end));if ((block > 255) || (block < 0)) {Log.w(TAG, "isValidIpAddress() : invalid 'block', block = " + block);return false;}} catch (NumberFormatException e) {Log.w(TAG, "isValidIpAddress() : e = " + e);return false;}numBlocks++;start = end + 1;end = value.indexOf('.', start);}return numBlocks == 4;}private boolean isIpDataInUiComplete() {ContentResolver contentResolver = getContentResolver();for (int i = 0; i < (mPreferenceKeys.length - 1); i++) {EditTextPreference preference = (EditTextPreference) findPreference(mPreferenceKeys[i]);String text = preference.getText();LOG("isIpDataInUiComplete() : text = " + text);if ( null == text || TextUtils.isEmpty(text) ) {return false;}}return true;}}

到这一步 Settings 的修改就完成了,就能实现上图的效果了,你可以mm push看效果了

如果你编译报错,大概是 Settings 中没有添加对应的变量,我的本来就有的,

没有的可参考下面的加一下

frameworks\base\core\java\android\provider\Settings.java
 

// Intent actions for Settings
// ethernet
public static final String ETHERNET_STATIC_IP = "ethernet_static_ip";
public static final String ETHERNET_STATIC_GATEWAY = "ethernet_static_gateway";
public static final String ETHERNET_STATIC_NETMASK = "ethernet_static_netmask";
public static final String ETHERNET_STATIC_DNS1 = "ethernet_static_dns1";
public static final String ETHERNET_STATIC_DNS2 = "ethernet_static_dns2";
public static final String IS_ETHERNET_OPEN = "isEthernetOpen";
public static final String IS_ETHERNET_STATUC_OPEN = "isEthernetStaticOpen";

加完后你需要先 make update-api成功后,在重新 mm 编译应该就好了

二、framework 流程分析

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

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

public final class EthernetService extends SystemService {private static final String TAG = "EthernetService";final EthernetServiceImpl mImpl;public EthernetService(Context context) {super(context);mImpl = new EthernetServiceImpl(context);}@Overridepublic void onStart() {Log.i(TAG, "Registering service " + Context.ETHERNET_SERVICE);publishBinderService(Context.ETHERNET_SERVICE, mImpl);}@Overridepublic void onBootPhase(int phase) {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

    public void start() {Log.i(TAG, "Starting Ethernet service");HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");handlerThread.start();mHandler = new Handler(handlerThread.getLooper());mTracker = new EthernetTracker(mContext, mHandler);mTracker.start();mStarted.set(true);
}

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

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

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();Log.e(TAG, "mIpConfigForDefaultInterface== " + mIpConfigForDefaultInterface);Log.i(TAG, "IpConfiguration size== " + configs.size());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);}

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

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();}private void parseEthernetConfig(String configString) {String[] tokens = configString.split(";");String name = tokens[0];String capabilities = tokens.length > 1 ? tokens[1] : null;NetworkCapabilities nc = createNetworkCapabilities(!TextUtils.isEmpty(capabilities)  /* clear default capabilities */, capabilities);mNetworkCapabilities.put(name, nc);if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) {IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]);mIpConfigurations.put(name, ipConfig);}}

config_ethernet_interfaces 的初始值位置在

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

<!-- Regex of wired ethernet ifaces --><string translatable="false" name="config_ethernet_iface_regex">eth\\d</string><!-- Configuration of Ethernet interfaces in the following format:<interface name|mac address>;[Network Capabilities];[IP config]Where[Network Capabilities] Optional. A comma seprated list of network capabilities.Values must be from NetworkCapabilities#NET_CAPABILITIES_* constants.[IP config] Optional. If empty or not specified - DHCP will be used, otherwiseuse the following format to specify static IP configuration:ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>domains=<comma-sep-domains> --><string-array translatable="false" name="config_ethernet_interfaces"><!--<item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=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 通过 mFactory addInterface,再然后 updateInterfaceState 广播通知当前以太网连接状态 CONNECTED/CONNECTED
 

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)) {Log.d(TAG, iface + "  return ");return;}Log.e(TAG, "maybeTrackInterface " + iface);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);}}private void updateInterfaceState(String iface, boolean up) {Log.e(TAG, "updateInterfaceState up==" + up);boolean modified = mFactory.updateInterfaceLinkState(iface, up);if (modified) {boolean restricted = isRestrictedInterface(iface);int n = mListeners.beginBroadcast();for (int i = 0; i < n; i++) {try {if (restricted) {ListenerInfo listenerInfo = (ListenerInfo) mListeners.getBroadcastCookie(i);if (!listenerInfo.canUseRestrictedNetworks) {continue;}}mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up);} catch (RemoteException e) {// Do nothing here.}}mListeners.finishBroadcast();}}

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

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

public class EthernetServiceImpl extends IEthernetManager.Stub {private static final String TAG = "EthernetServiceImpl";public static final String IS_ETHERNET_OPEN = Settings.IS_ETHERNET_OPEN;public static final String ETHERNET_USE_STATIC_IP = Settings.IS_ETHERNET_STATUC_OPEN; private final Context mContext;private final AtomicBoolean mStarted = new AtomicBoolean(false);private IpConfiguration mIpConfiguration;private final EthernetOpenedObserver mOpenObserver = new EthernetOpenedObserver();private final EthernetStaticObserver mStaticObserver = new EthernetStaticObserver(); private Handler mHandler;private EthernetTracker mTracker;public EthernetServiceImpl(Context context) {mContext = context;Log.i(TAG, "Creating EthernetConfigStore");mContext.getContentResolver().registerContentObserver(System.getUriFor(IS_ETHERNET_OPEN), false, mOpenObserver);mContext.getContentResolver().registerContentObserver(System.getUriFor(ETHERNET_USE_STATIC_IP), false, mStaticObserver); }....public void start() {Log.i(TAG, "Starting Ethernet service");HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");handlerThread.start();mHandler = new Handler(handlerThread.getLooper());mTracker = new EthernetTracker(mContext, mHandler);mIpConfiguration = mTracker.getDefaultIpConfiguration();if (getState() == 1) {                 if (isStatic()) {StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();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 = new LinkAddress(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 (Exception e){e.printStackTrace();}mIpConfiguration.ipAssignment = IpAssignment.STATIC;mIpConfiguration.proxySettings = ProxySettings.STATIC;mIpConfiguration.staticIpConfiguration = staticIpConfiguration;}mTracker.start();mStarted.set(true);}  }private boolean isStatic(){Log.e(TAG, "EthernetServiceImpl isStatic()  " + Settings.System.getInt(mContext.getContentResolver(),ETHERNET_USE_STATIC_IP,0));return Settings.System.getInt(mContext.getContentResolver(),ETHERNET_USE_STATIC_IP,0) ==1;}   private int getState(){int state = Settings.System.getInt(mContext.getContentResolver(), IS_ETHERNET_OPEN,0);Log.e(TAG, "EthernetServiceImpl getState()  " + state);return state;}....@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();}Log.e(TAG, "setConfiguration iface="+iface);// 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));//addmTracker.removeInterface(iface);mTracker.start();}....private final class EthernetOpenedObserver extends ContentObserver {public EthernetOpenedObserver() {super(new Handler());}@Overridepublic void onChange(boolean selfChange, Uri uri, int userId) {super.onChange(selfChange, uri, userId);Log.i(TAG, "EthernetServiceImpl isEthernetOpen onChange....");if (getState() == 1) {if (isStatic()) {StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();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 = new LinkAddress(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 (Exception e){e.printStackTrace();}mIpConfiguration.ipAssignment = IpAssignment.STATIC;mIpConfiguration.proxySettings = ProxySettings.STATIC;mIpConfiguration.staticIpConfiguration = staticIpConfiguration;}mTracker.start();mStarted.set(true);}else {    mTracker.stop();        }}}private final class EthernetStaticObserver extends ContentObserver {public EthernetStaticObserver() {super(new Handler());}@Overridepublic void onChange(boolean selfChange, Uri uri, int userId) {super.onChange(selfChange, uri, userId);Log.i(TAG, "EthernetServiceImpl isEthernetStaticOpen onChange....");if (!isStatic()) {Log.e(TAG, " no static stop and start");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, 不然关闭后无法再次打开,因为上面提到的判断
public void stop() {Log.d(TAG, "EthernetTracker stop ethernet...");updateInterfaceState("eth0", false);android.os.SystemClock.sleep(200);removeInterface("eth0");}//获取默认的 IpConfiguration,如果不存在则新建一个 DHCP 类型的,根据实际情况修改 ipAssignment 和 proxySettings
public IpConfiguration getDefaultIpConfiguration(){IpConfiguration ipConfiguration = mIpConfigurations.get("eth0");return ipConfiguration != null ? ipConfiguration : new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null);
}//从静态 IP 切换
public void recoverDHCPIpConfiguration(){mIpConfigurations.put("eth0", new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null));
}

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/221799.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

集合04 Collection (Set) - Java

Set Set 基本介绍Set 常用方法Set 遍历方式 HashSet 的全面说明练习 HashSet 的底层机制说明HashSet 的扩容机制&转成红黑树机制练习1练习2 LinkedHashSetLinkedHashSet底层源码练习 Set 基本介绍 无序&#xff08;添加和取出的顺序不一致)&#xff0c;没有索引 [后面演示…

【Java系列】详解多线程(二)——Thread类及常见方法(下篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一…

大模型微调的“温度”参数,原来影响的是 softmax

大家好啊&#xff0c;我是董董灿。 在对大模型进行微调训练时&#xff0c;经常会看到几个重要的超参数&#xff0c;用来控制大模型生成文本的效果。 其中一个超参数叫做 Temperature&#xff0c;中文名字叫温度&#xff0c;初见时很是不解&#xff0c;为啥一个模型还有温度这个…

将创建表字段语句快速转换成golang struct字段

用网页jquery快速生成 本地建立 struct.html <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>leo-转换</title> <script src"https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></s…

深入学习《大学计算机》系列之第1章 1.2节——问题描述与抽象

一.欢迎来到我的酒馆 第1章 1.2节&#xff0c;问题描述与抽象。 目录 一.欢迎来到我的酒馆二.问题描述、抽象与建模1.什么是抽象2.为什么要抽象3.什么是建模 二.问题描述、抽象与建模 什么是抽象&#xff1f;为什么要抽象&#xff1f;什么是建模&#xff1f;建什么模&#xff1…

Windows安装Elasticsearch并结合内网穿透实现公网远程访问

Windows安装Elasticsearch并结合内网穿透实现公网远程访问 系统环境1. Windows 安装Elasticsearch2. 本地访问Elasticsearch3. Windows 安装 Cpolar4. 创建Elasticsearch公网访问地址5. 远程访问Elasticsearch6. 设置固定二级子域名 Elasticsearch是一个基于Lucene库的分布式搜…

[Longformer]论文实现:Longformer: The Long-Document Transformer

文章目录 一、完整代码二、论文解读2.1 介绍2.2 Longformer注意力模式注意力计算 2.3 自回归语言模型注意力模式训练结果 2.4 预训练和微调注意力模式位置编码预训练结果 2.5 Longformer-Encoder-Decoder (LED) 三、整体总结 论文&#xff1a;Longformer: The Long-Document Tr…

wordpress:6.3的docker部署和k8s部署方式

wordpress:6.3的docker部署 一.docker部署mysql5.7数据库 docker pull mysql:5.7 mkdir -p /data/mysql/data /data/mysql/logs /data/mysql/conf touch /data/mysql/conf/my.cnf docker run --restartalways -p 13306:3306 --name mysql -v /data/mysql/conf:/etc/mysql/con…

std::vector

这里主要介绍下reserce/resize、push_back/emplace_back、shrink_to_fit/clear等接口&#xff1b; 1. reserve and resize C的vector对象可以通过reserve方法来设置vector对象的容量&#xff0c;通过resize方法来改变vector对象的大小。reserve所设置的容量指的是vector容器中可…

网工内推 | IT经理,50k*14薪,NP以上即可,七险一金

01 海天瑞声 招聘岗位&#xff1a;IT经理 职责描述&#xff1a; 1、IT基础架构的方案制定、实施和日常维护&#xff0c;包括机房建设运维、服务器配置及运维、网络规划及运维、上网行为管理、电话、电话、监控、门禁等各类弱电系统搭建及运维 2、负责公司环境及网络安全防御体…

Vue 按键修饰符

常用按键修饰符&#xff1a;enter【回车】、delete【删除】、esc【退出】、space【空格】、tab【缩进】、up【上】、down【下】、left【左】、right【右】 。 系统按键修饰符&#xff1a;ctrl、alt、shift、meta【四个小方块】 。 鼠标修饰符&#xff1a;left【左键】、right…

Chip and Ribbon Educational Codeforces Round 158 (Rated for Div. 2)

Problem - B - Codeforces 题目大意&#xff1a;有一个n个数的数组a&#xff0c;有一个初始等于1的指针&#xff0c;有两种操作&#xff1a; 1.设指针当前位置为l&#xff0c;可以选择一个任意位置r(r>l)&#xff0c;使[l,r]内所有数1 2.将指针移动到一个任意位置&#x…

ubuntu 自动安装 MKL Intel fortran 编译器 ifort 及完美平替

首先据不完全观察&#xff0c;gfortran 与 openblas是 intel fortran 编译器 ifotr和mkl的非常优秀的平替&#xff0c;openblas连函数名都跟mkl一样&#xff0c;加了一个下划线。 1&#xff0c; 概况 https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-too…

配电房电力智能运维系统

配电房电力智能运维系统是一种采用先进的信息技术手段&#xff0c;对配电房的电力设备进行实时监控、数据分析和管理的系统。它能够提高电力设备的安全性和效率&#xff0c;降低运维成本&#xff0c;为用户提供更加优质、高效的电力服务。 该系统依托智能运维工具-电易云&#…

PCL点云处理之反算两块点云的放缩比例 (二百二十三)

PCL点云处理之反算两块点云的放缩比例 (二百二十三) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 在 PCL点云处理之等比例放大与缩小点云尺寸(七十二)一章中,介绍了如何等比例放大缩小一块点云,这里介绍如何反算得到两片经过放缩的点云之间的比例,这种计算方法应…

关系型数据库和非关系型数据库有什么区别?

一、什么是数据库&#xff1f; 数据库是一个结构化的数据集合&#xff0c;用于存储、管理和组织数据。它是一个电子化的文件柜&#xff0c;可以存储大量的数据&#xff0c;并提供了一种高效地检索、更新和管理数据的方法。数据库可以用于存储各种类型的数据&#xff0c;例如文…

【排序算法】之归并排序

归并思想 先拆分后合并 也就是分治&#xff1b; 拆分合并思想具体讲解可以参考以下链接&#xff1a; b站链接&#xff1a; 点这里&#xff1a;b站归并思想具体讲解 看代码 代码中的例子参考上图和下图 public class MergeSort {//一、拆分部分public static void split(i…

springcloud getway 网关之过滤器filter

1. Filter的使用 filter是Gateway的三大核心之一&#xff0c;路由过滤器可用于修改进入HTTP请求和返回的HTTP响应&#xff0c;路由过滤器只能指定路由进行使用。Gateway内置了多种路由过滤器&#xff0c;他们都由GatewayFilter工程 2. Filter的作用 当我们有很多个服务时&am…

【机器学习 | 假设检验系列】假设检验系列—卡方检验(详细案例,数学公式原理推导),最常被忽视得假设检验确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

2024 年,新程序员如何与AI共赢!!

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…