Android 9 系统设置中添加以太网开关按钮
本章突出新手可以简单快速实现该需求。(具体以太网流程自行百度)
首先在系统Settings设置选项中添加选项。(该部分逻辑以及如何在获取设置按钮的开关状态,不在这里介绍,过往有做过介绍)
这里采用广播的方式通知framework层去开关以太网。
Android P 对广播做了保护
因此我们需要在/frameworks/base/core/res/AndroidManifest.xml中定义我们的广播
广播名称可以随意定义,注意勿重复!
接着就是最关键部分
frameworks/opt/net/ethernet/java/com/android/server/ethernet/EthernetTracker.java
先看代码:
package com.android.server.ethernet;
...
final class EthernetTracker {
private final static String TAG = EthernetTracker.class.getSimpleName();
private final static boolean DBG = EthernetNetworkFactory.DBG;
/** Product-dependent regular expression of interface names we track. */
private final String mIfaceMatch;
/** Mapping between {iface name | mac address} -> {NetworkCapabilities} */
private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities =
new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, IpConfiguration> mIpConfigurations =
new ConcurrentHashMap<>();
private final INetworkManagementService mNMService;
private final Handler mHandler;
private final EthernetNetworkFactory mFactory;
private final EthernetConfigStore mConfigStore;
private final RemoteCallbackList<IEthernetServiceListener> mListeners =
new RemoteCallbackList<>();
private volatile IpConfiguration mIpConfigForDefaultInterface;
+ private Context mContext;
+ String eth0Action = "android.eth0.power.status";
EthernetTracker(Context context, Handler handler) {
mHandler = handler;
+ mContext = context;
// 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 resources
final 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();
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(eth0Action);
+ mContext.registerReceiver(new EthBroadcast(), intentFilter);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ Log.d("yy", "run auto update eht0 power after 5s. tips: def is true");
+ setInterfaceStatus(SystemProperties.get("persist.sys.edu.eth0.power","1").equals("1"));
+ }
+ }, 5000);
+ }
+ class EthBroadcast extends BroadcastReceiver{
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() != null) {
+ if (intent.getAction().equals(eth0Action)) {
+ boolean power = intent.getBooleanExtra("power", true);
+ Log.d("yy", "EthBroadcast onReceive: "+power);
+ SystemProperties.set("persist.sys.edu.eth0.power",power?"1":"0");
+ setInterfaceStatus(power);
+
+ }
+ }
+ }
+ }
+ public boolean setInterfaceStatus(boolean state){
+ Log.d("yy", "setInterfaceStatus: state:"+state);
+ try {
+ if(!TextUtils.isEmpty("eth0")) {
+ if(!state)
+ mNMService.setInterfaceDown("eth0");
+ else
+ mNMService.setInterfaceUp("eth0");
+ return true;
+ } else {
+ Log.e("yy","iface is null");
+ }
+ } catch (Exception e) {
+ Log.e("yy", "Error setInterfaceStatus : " + "eth0" + " state : " + state + " exception : " + e);
+ }
+ return false;
}
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);
}
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));
}
IpConfiguration getIpConfiguration(String iface) {
return mIpConfigurations.get(iface);
}
boolean isTrackingInterface(String iface) {
return mFactory.hasInterface(iface);
}
String[] getInterfaces(boolean includeRestricted) {
return mFactory.getAvailableInterfaces(includeRestricted);
}
/**
* Returns true if given interface was configured as restricted (doesn't have
* NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false.
*/
boolean isRestrictedInterface(String iface) {
final NetworkCapabilities nc = mNetworkCapabilities.get(iface);
return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) {
mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks));
}
void removeListener(IEthernetServiceListener listener) {
mListeners.unregister(listener);
}
void removeInterface(String iface) {
mFactory.removeInterface(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 address
nc = 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) {
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();
}
}
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 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 class InterfaceObserver extends BaseNetworkObserver {
@Override
public void interfaceLinkStateChanged(String iface, boolean up) {
if (DBG) {
Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
}
mHandler.post(() -> updateInterfaceState(iface, up));
}
@Override
public void interfaceAdded(String iface) {
mHandler.post(() -> maybeTrackInterface(iface));
}
@Override
public void interfaceRemoved(String iface) {
mHandler.post(() -> removeInterface(iface));
}
}
private static class ListenerInfo {
boolean canUseRestrictedNetworks = false;
ListenerInfo(boolean canUseRestrictedNetworks) {
this.canUseRestrictedNetworks = canUseRestrictedNetworks;
}
}
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);
}
}
private static NetworkCapabilities createDefaultNetworkCapabilities() {
NetworkCapabilities nc = createNetworkCapabilities(false /* clear default capabilities */);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
return nc;
}
private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) {
return createNetworkCapabilities(clearDefaultCapabilities, null);
}
private static NetworkCapabilities createNetworkCapabilities(
boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities) {
NetworkCapabilities nc = new NetworkCapabilities();
if (clearDefaultCapabilities) {
nc.clearAll(); // Remove default capabilities.
}
nc.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
nc.setLinkUpstreamBandwidthKbps(100 * 1000);
nc.setLinkDownstreamBandwidthKbps(100 * 1000);
if (!TextUtils.isEmpty(commaSeparatedCapabilities)) {
for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) {
if (!TextUtils.isEmpty(strNetworkCapability)) {
nc.addCapability(Integer.valueOf(strNetworkCapability));
}
}
}
return nc;
}
/**
* Parses static IP configuration.
*
* @param staticIpConfig represents static IP configuration in the following format: {@code
* ip= gateway= dns=
* domains=}
*/
@VisibleForTesting
static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) {
StaticIpConfiguration ipConfig = new StaticIpConfiguration();
for (String keyValueAsString : staticIpConfig.trim().split(" ")) {
if (TextUtils.isEmpty(keyValueAsString)) continue;
String[] pair = keyValueAsString.split("=");
if (pair.length != 2) {
throw new IllegalArgumentException("Unexpected token: " + keyValueAsString
+ " in " + staticIpConfig);
}
String key = pair[0];
String value = pair[1];
switch (key) {
case "ip":
ipConfig.ipAddress = new LinkAddress(value);
break;
case "domains":
ipConfig.domains = value;
break;
case "gateway":
ipConfig.gateway = InetAddress.parseNumericAddress(value);
break;
case "dns": {
ArrayList<InetAddress> dnsAddresses = new ArrayList<>();
for (String address: value.split(",")) {
dnsAddresses.add(InetAddress.parseNumericAddress(address));
}
ipConfig.dnsServers.addAll(dnsAddresses);
break;
}
default : {
throw new IllegalArgumentException("Unexpected key: " + key
+ " in " + staticIpConfig);
}
}
}
return new IpConfiguration(IpAssignment.STATIC, ProxySettings.NONE, ipConfig, null);
}
private static IpConfiguration createDefaultIpConfiguration() {
return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null);
}
private void postAndWaitForRunnable(Runnable r) {
mHandler.runWithScissors(r, 2000L /* timeout */);
}
void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
postAndWaitForRunnable(() -> {
pw.println(getClass().getSimpleName());
pw.println("Ethernet interface name filter: " + mIfaceMatch);
pw.println("Listeners: " + mListeners.getRegisteredCallbackCount());
pw.println("IP Configurations:");
pw.increaseIndent();
for (String iface : mIpConfigurations.keySet()) {
pw.println(iface + ": " + mIpConfigurations.get(iface));
}
pw.decreaseIndent();
pw.println();
pw.println("Network Capabilities:");
pw.increaseIndent();
for (String iface : mNetworkCapabilities.keySet()) {
pw.println(iface + ": " + mNetworkCapabilities.get(iface));
}
pw.decreaseIndent();
pw.println();
mFactory.dump(fd, pw, args);
});
}
}
上述修改:在EthernetTracker中注册广播监听器,监听setting按钮状态,
然后mNMService.setInterfaceDown(“eth0”);和mNMService.setInterfaceUp(“eth0”);开关以太网!