参考文章:
Android 以太网/有线网Ethernet功能开发
以太网插拔
上文是在EthernetManager(frameworks\base\core\java\android\net\EthernetManager)中添加接口onEthernetIfaceRemove()
:
/**
* A listener interface to receive notification on changes in Ethernet.
*/
public interface Listener {
/**
* Called when Ethernet port's availability is changed.
* @param isAvailable {@code true} if one or more Ethernet port exists.
*/
public void onAvailabilityChanged(boolean isAvailable);
/*
*Called when network wire take out
*/
public void onEthernetIfaceRemove();
}
这种方法很容易导致其他应用因为没有实现onEthernetIfaceRemove()
方法而出异常,所以应该放在单独的Listener中。
我们来看EthernetManager中原来的Listener工作流程:
我们实现一般使用时是实现EthernetManager.Listener接口,实现已有的onAvailabilityChanged(boolean isAvailable)
方法,如TvSettings中的ConnectivityListener中的:
private final EthernetManager.Listener mEthernetListener = new EthernetManager.Listener() {
@Override
public void onAvailabilityChanged(boolean isAvailable) {
mListener.onConnectivityChange(null);
}
};
然后使用时需要添加这个listener:
EthernetManager mEthernetManager = (EthernetManager) mContext.getSystemService(Context.ETHERNET_SERVICE);
.......
......
mEthernetManager.addListener(mEthernetListener);
不使用时去除这个listener:
mEthernetManager.removeListener(mEthernetListener);
一般这两个方法需要成对出现。
/**
* Adds a listener.
* @param listener A {@link Listener} to add.
* @throws IllegalArgumentException If the listener is null.
*/
public void addListener(Listener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
mListeners.add(listener);
if (mListeners.size() == 1) {
try {
mService.addListener(mServiceListener);
} catch (NullPointerException | RemoteException e) {
}
}
}
/**
* Removes a listener.
* @param listener A {@link Listener} to remove.
* @throws IllegalArgumentException If the listener is null.
*/
public void removeListener(Listener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
mListeners.remove(listener);
if (mListeners.isEmpty()) {
try {
mService.removeListener(mServiceListener);
} catch (NullPointerException | RemoteException e) {
}
}
}
private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
EthernetManager在添加listener时将新的listener存放在本地的列表中,同时在列表数大于0时通过方法mService.addListener(mServiceListener);
将本地实现的接口也添加到了EthernetServiceImpl中。
本地实现的接口:
private final IEthernetServiceListener.Stub mServiceListener =
new IEthernetServiceListener.Stub() {
@Override
public void onAvailabilityChanged(boolean isAvailable) {
mHandler.obtainMessage(
MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, null).sendToTarget();
}
};
接口的方法在framework\base\core\java\android\net\IEthernetServiceListener.aidl
中定义,当回调方法运行时mHandler发送消息,遍历本地的listener列表逐个通知:
rivate final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_AVAILABILITY_CHANGED) {
boolean isAvailable = (msg.arg1 == 1);
for (Listener listener : mListeners) {
listener.onAvailabilityChanged(isAvailable);
}
}
}
};
接下来看EthernetServiceImpl中的流程:
EthernetServiceImpl继承IEthernetManager.Stub,方法在framework\base\core\java\android\net\IEthernetManager.aidl
中定义
interface IEthernetManager
{
IpConfiguration getConfiguration();
void setConfiguration(in IpConfiguration config);
boolean isAvailable();
void addListener(in IEthernetServiceListener listener);
void removeListener(in IEthernetServiceListener listener);
}
在EthernetManager中调用addListener方法之后
/**
* Addes a listener.
* @param listener A {@link IEthernetServiceListener} to add.
*/
public void addListener(IEthernetServiceListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
enforceAccessPermission();
mListeners.register(listener);
}
mListeners:
private final RemoteCallbackList<IEthernetServiceListener> mListeners =
new RemoteCallbackList<IEthernetServiceListener>();
RemoteCallbackList也是一个集合,将注册的listener保存起来,在EthernetServiceImpl的构造方法中,这个集合被传递到EthernetNetworkFactory中:
public EthernetServiceImpl(Context context) {
mContext = context;
Log.i(TAG, "Creating EthernetConfigStore");
mEthernetConfigStore = new EthernetConfigStore();
mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);
mTracker = new EthernetNetworkFactory(mListeners);
}
在EthernetNetworkFactory中:有方法表现网络变化
private class InterfaceObserver extends BaseNetworkObserver {
@Override
public void interfaceLinkStateChanged(String iface, boolean up) {
updateInterfaceState(iface, up);
}
@Override
public void interfaceAdded(String iface) {
maybeTrackInterface(iface);
}
@Override
public void interfaceRemoved(String iface) {
stopTrackingInterface(iface);
}
}
其中iface可能是wlan,usbnet0等,可以在此做出区分处理。
对于以太网而言,方法interfaceLinkStateChanged
是用来处理网口的开关的,interfaceAdded是网线插入,interfaceRemoved是网线拔出。
interfaceAdded方法中调用了maybeTrackInterface(iface);
方法
private boolean maybeTrackInterface(String iface) {
// If we don't already have an interface, and if this interface matches
// our regex, start tracking it.
boolean match = false;
for (String item : mUsbIfaceMatchs) {
if (iface.matches(item)) {
match = true;
}
}
if (iface.matches(mIfaceMatch)){ // || isTrackingInterface()) {
match = true;
}
if (!match) {
Log.v(TAG, "didn't find a match iface:"+ iface);
return false;
}
Log.v(TAG, "add interface[" +iface+"] to IfaceStack");
mIfaceStack.add(iface);
if (mIfaceStack.size() > 1) {
setInterfaceCanUp(iface);
return true;
}
Log.d(TAG, "Started tracking interface " + iface);
setInterfaceUp(iface);
return true;
}
当调用到 setInterfaceUp(iface);
时,setInterfaceUp方法会设置相应的网络信息,并调用setInterfaceInfoLocked(iface, config.getHardwareAddress());
方法遍历所有注册的listener通知onAvailabilityChanged
,拔出时流程类似。
所以这样梳理一次后就知道怎么做了:
先在EthernetNetworkFactory中保存一个全局变量
private boolean isEthernetAdded = false;
修改InterfaceObserver 用于保存网线的状态(此处只以usb转以太网为例,所以用的usbnet0过滤):
private class InterfaceObserver extends BaseNetworkObserver {
@Override
public void interfaceLinkStateChanged(String iface, boolean up) {
updateInterfaceState(iface, up);
if("usbnet0".equals(iface)){
Log.i(TAG,"interfaceLinkStateChanged---linked:"+up);
isEthernetAdded = up;
}
}
@Override
public void interfaceAdded(String iface) {
maybeTrackInterface(iface);
if("usbnet0".equals(iface)){
Log.i(TAG,"interfaceAdded");
isEthernetAdded = true;
notifyEthernetInjected(isEthernetAdded);
}
}
@Override
public void interfaceRemoved(String iface) {
stopTrackingInterface(iface);
if("usbnet0".equals(iface)){
Log.i(TAG,"interfaceRemoved");
isEthernetAdded = false;
notifyEthernetInjected(isEthernetAdded);
}
}
}
添加方法来通知所有注册的listener
private void notifyEthernetInjected(boolean isInjected){
int n = mListeners.beginBroadcast();
Log.i(TAG,"notifyEthernetInjected state listener size : "+n+",isInjected:"+isInjected);
for (int i = 0; i < n; i++) {
try {
mListeners.getBroadcastItem(i).onEthernetInjected(isInjected);
} catch (RemoteException e) {
// Do nothing here.
}
}
mListeners.finishBroadcast();
}
添加方法获取本地的变量:
public synchronized boolean isEthernetInjected(){
return isEthernetAdded;
}
notifyEthernetInjected方法中调用到的onEthernetInjected
方法需在EthernetManager中添加:
private final IEthernetServiceListener.Stub mServiceListener =
new IEthernetServiceListener.Stub() {
@Override
public void onAvailabilityChanged(boolean isAvailable) {
mHandler.obtainMessage(
MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, null).sendToTarget();
}
@Override
public void onEthernetInjected(boolean isInjected) {
Log.i(TAG,"onEthernetInjected---isInjected:"+isInjected);
mHandler.obtainMessage(MSG_ETHERNET_INJECTION_CHANGED,isInjected).sendToTarget();
}
};
同时需在IEthernetServiceListener.aidl中添加此方法:
oneway interface IEthernetServiceListener
{
void onAvailabilityChanged(boolean isAvailable);
void onEthernetInjected(boolean isInjected);//added by xuliangchao 20180731 to detect whether the ethernet is injected
}
然后在EthernetManager中接收mHandler发送的消息MSG_ETHERNET_INJECTION_CHANGED:
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_AVAILABILITY_CHANGED) {
boolean isAvailable = (msg.arg1 == 1);
for (Listener listener : mListeners) {
listener.onAvailabilityChanged(isAvailable);
}
}
else if(msg.what == MSG_ETHERNET_INJECTION_CHANGED){
boolean isInjected = (boolean)msg.obj;
for (EthernetListener listener : mEthernetListeners) {
listener.onEthernetInjected(isInjected);
}
}
}
};
其中mEthernetListeners是上另外一个列表,用来存放EthernetListener:
private final ArrayList<EthernetListener> mEthernetListeners = new ArrayList<EthernetListener>();
public interface EthernetListener {
public void onEthernetInjected(boolean isEthernetInjected);
}
还需要add和remove方法:
public void addEthernetListener(EthernetListener listener){
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
mEthernetListeners.add(listener);
}
public void removeEthernetListener(EthernetListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
mEthernetListeners.remove(listener);
}
这里没有像addListener方法中调用mService.addListener(mServiceListener);
是因为本人Listener和EthernetListener基本会一起用,所以为了避免重复添加就没有添加这段代码。
至此,实时上报的以太网拔接口已经实现。
另外,刚刚在EthernetNetworkFactory中有个isEthernetInjected()
方法,要想在EthernetManager中调用此方法,需在IEthernetManager.aidl中添加方法:
interface IEthernetManager
{
IpConfiguration getConfiguration();
void setConfiguration(in IpConfiguration config);
boolean isAvailable();
void addListener(in IEthernetServiceListener listener);
void removeListener(in IEthernetServiceListener listener);
boolean isEthernetInjected();
}
这些方法均是在EthernetServiceImpl中实现:
@Override
public boolean isEthernetInjected() {
enforceAccessPermission();
return mTracker.isEthernetInjected();
}
这样就调用到了EthernetNetworkFactory中的isEthernetInjected()
方法,最后在EthernetManager中添加方法:
public boolean isEthernetInjected() {
try {
return mService.isEthernetInjected();
} catch (NullPointerException | RemoteException e) {
return false;
}
}
至此全部实现,文章写的有点乱,希望能看懂。