android ethernet 框架,Android Ethernet从上至下解析一

Android Ethernet从上至下解析一

浏览次数:

发布时间:2015-08-30 14:14

最近遇到不少框架问题,比如关于网口的,开机后拔掉有线网,状态栏和设置项中有线网显示图标不会更新,还有双网口的需求,下面就带着这个问题,以跟踪网络状态问题为引线,本篇将贯穿分析Ethernet从上至下的框架结构。因能力和时间有限,文中有分析不到位的地方,十分欢迎大侠们拍砖。

首先看下应用层网络监听相关的app 网络监听一:设置 packages/apps/Settings/src/com/android/settings/ethernet/EthernetEnabler.java

设置项网络按钮类定义

网络监听二:statusbar frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java

NetworkController本身是个BroadcastReceiver,其中关于网络状态变化的监听消息为EthernetManager.NETWORK_STATE_CHANGED_ACTION,可以猜测这个消息是framework发出来的,往下看。

网络服务框架层 通过整理,网络框架管理器和服务相关代码和基本解释如下: frameworks/base/ethernet/java/com/android/internal/ethernet/

EthernetStateMachine.java

-> 网络状态机,用于管理网络状态变化及动作逻辑

EthernetManager.java

-> 网络管理器,是app和EthernetService信息交互的桥梁

EthernetInfo.java

-> 网络状态参数类,是Parcelable的一个实现

EthernetInfo.aidl

-> aidl文件,Manager和service统一使用的数据结构

IEthernetManager.aidl

-> aidl文件,用于Manager和service通信

在此可以发现网络状态机也在监听NETWORK_STATE_CHANGED_ACTION广播,广播发送者不再这里,那应该就是在service那了,继续往下。 frameworks/base/services/java/com/android/server/EthernetService.java

private class InterfaceStateReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

if (intent.getAction().equals(EthernetManager.INTERFACE_STATE_CHANGED_ACTION)) {

...

Intent newIntent = new Intent(EthernetManager.NETWORK_STATE_CHANGED_ACTION);

newIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);

newIntent.putExtra(EthernetManager.EXTRA_ETHERNET_INFO, ei);

在service中,可以看到发送NETWORK_STATE_CHANGED_ACTION的发送动作,而这个发送行为还不是底层上报的状态直接启动的,而是上面说的网络状态机,它发送的INTERFACE_STATE_CHANGED_ACTION广播信息,怎么源头又跑上面去了?有些人可能并不理解为什么在framework里面要把一个简单的事件广播要这么来回的发送,等明白了网络状态机的作用,就知道这些过程的逻辑性了。

我们知道statemachine的特点是有一个rootstate,然后向下由多个state发展而成一个树状结构,state之间的转换会伴随着enter(),processMessage()等动作。EthernetStateMachine的状态初始化如下:

addState(mRootState);

addState(mIdleState, mRootState);

//addState(mObtainingLinkState, mRootState);

addState(mObtainingIpState, mRootState);

addState(mIPConnectedState, mRootState);

addState(mDisconnectingState, mRootState);

接着前面说到的INTERFACE_STATE_CHANGED_ACTION广播继续来看下状态机中的逻辑。 在ethernetstatemachine中,state状态的变化控制着网络状态的广播通知,部分代码如下:

private void sendInterfaceStateChangedBroadcast() {

if (DBG) Slog.d(TAG, Sending INTERFACE_STATE_CHANGED_ACTION for

+ mEthernetInfo.getName());

Intent intent = new Intent(EthernetManager.INTERFACE_STATE_CHANGED_ACTION);

intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);

intent.putExtra(EthernetManager.EXTRA_ETHERNET_INFO, new EthernetInfo(mEthernetInfo));

mContext.sendBroadcast(intent);

}

private void setNetworkDetailedState(DetailedState state) {

if (DBG) Slog.d(TAG, mEthernetInfo.getName() + setDetailed state, old =

+ mEthernetInfo.getDetailedState() + and new state= + state);

if (state != mEthernetInfo.getDetailedState()) {

mEthernetInfo.setDetailedState(state, null, null);

mEthernetInfo.setIsAvailable(true);

sendInterfaceStateChangedBroadcast();

}

}

void dhcpSuccess(DhcpResults dr) {

if (DBG) Slog.d(TAG, mEthernetInfo.getName() + DHCP successful);

LinkProperties lp = dr.linkProperties;

...

setNetworkDetailedState(DetailedState.CONNECTED);

}

上面就是网络状态机的逻辑功能,而状态机的消息来源是service,

public void updateInterface(EthernetInfo newInfo) {

if (newInfo == null) {

Slog.e(TAG, Null EthernetInfo);

return;

}

if (mAvailableInterface == null) {

Slog.e(TAG, Unable to find statemachine for interface + newInfo.getName());

return;

}

sendMessage(mAvailableInterface,

EthernetStateMachine.CMD_UPDATE_INTERFACE,

newInfo);

if(DBG) Slog.d(TAG, newInfo.getName() + updateInterface done);

}

看到了来来回回的广播,至此算是结束了,这里还要注意一点,广播收发程序中,我们要注意一个序列化参数的传递,就是EthernetInfo对象,这个对象存储着当前网络状态参数。

我们可以这么理解:网络状态机是EthernetService的辅助逻辑处理单元,service通过给状态机发送消息并等待状态机处理结果,然后将结果发送给应用程序。这个就是网络部分framework层的大致逻辑,了解这个之后,我们继续分析service是从哪里取得网络状态消息的。 来看下EthernetService的构造函数:

public EthernetService(Context context) {

mContext = context;

mNetd = INetworkManagementService.Stub.asInterface(

ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)

);

try {

mNetd.registerObserver(new NetworkManagementEventObserver());

} catch (RemoteException e) {

Slog.e(TAG, Remote NetworkManagementService error: + e);

}

看下NetworkManagementEventObserver的实现:

private class NetworkManagementEventObserver extends INetworkManagementEventObserver.Stub {

public void interfaceAdded(String iface) {

if(DBG) Slog.d(TAG, interfaceAdded: + iface);

addInterface(iface);

}

public void interfaceRemoved(String iface) {

if(DBG) Slog.d(TAG, interfaceRemoved: + iface);

removeInterface(iface);

}

public void limitReached(String limitName, String iface) {}

public void interfaceClassDataActivityChanged(String label, boolean active) {}

public void interfaceLinkStateChanged(String iface, boolean up) {

if(DBG) Slog.d(TAG, interfaceLinkStateChanged for + iface + , up = + up);

if (mAvailableInterface != null && up) {

//sendMessage(mAvailableInterface,

//EthernetStateMachine.CMD_LINK_UP);

}

}

public void interfaceStatusChanged(String iface, boolean up) {

if(DBG) Slog.d(TAG, interfaceStatusChanged for + iface + , up = + up);

//addInterface(iface);

}

public void addressUpdated(String address, String iface, int flags, int scope) {}

public void addressRemoved(String address, String iface, int flags, int scope) {}

}

这里我们看到seivice从NetworkManagementService进行函数回调。 NetworkManagementService也是注册到系统中的服务项,顾名思义负责网络管理服务,具体功能在本篇不做深入分析,其中之一通过socket和netd进行交互,这个在后面继续跟踪。

SystemServer.java try {

Slog.i(TAG, NetworkManagement Service);

networkManagement = NetworkManagementService.create(context);

ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);

} catch (Throwable e) {

reportWtf(starting NetworkManagement Service, e);

}

在后续的分析中,我们开始了解到framework到native的交互,这里我们先看一张网络的图示

我们按照图示的最上层来看看NetworkManagementService.java

private static final String NETD_SOCKET_NAME = netd;

private NetworkManagementService(Context context, String socket) {

mContext = context;

if (simulator.equals(SystemProperties.get(ro.product.device))) {

return;

}

mConnector = new NativeDaemonConnector(

new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160);

mThread = new Thread(mConnector, NETD_TAG);

// Add ourself to the Watchdog monitors.

Watchdog.getInstance().addMonitor(this);

}

这里socket值就是netd字符串,service启动了名为NativeDaemonConnector的Runnable线程,同时从构造函数中传递了NetdCallbackReceiver 对象,用于回调处理各种网络事件。

private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {

@Override

public void onDaemonConnected() {

@Override

public boolean onEvent(int code, String raw, String[] cooked) {

switch (code) {

case NetdResponseCode.InterfaceChange:

} else if (cooked[2].equals(linkstate) && cooked.length == 5) {

// 网络状态变化事件在这里回调处理

notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals(up));

return true;

}

/**

* Notify our observers of an interface link state change

* (typically, an Ethernet cable has been plugged-in or unplugged).

*/

private void notifyInterfaceLinkStateChanged(String iface, boolean up) {

final int length = mObservers.beginBroadcast();

for (int i = 0; i < length; i++) {

try {

mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);

} catch (RemoteException e) {

} catch (RuntimeException e) {

}

}

mObservers.finishBroadcast();

}

上面说了NativeDaemonConnector是一个Runnable的实现,那么这个线程在后台做些什么工作呢?在线程run函数中可以看到线程在while死循环中一直listenToSocket,可以猜想这里是在监听获取native中网络相关事件的地方了。

@Override

public void run() {

mCallbackHandler = new Handler(FgThread.get().getLooper(), this);

while (true) {

try {

listenToSocket();

} catch (Exception e) {

loge(Error in NativeDaemonConnector: + e);

SystemClock.sleep(5000);

}

}

}

private void listenToSocket() throws IOException {

LocalSocket socket = null;

try {

// 创建一个socket

socket = new LocalSocket();

LocalSocketAddress address = determineSocketAddress();

socket.connect(address);

// 从socket中获取流数据并处理

InputStream inputStream = socket.getInputStream();

synchronized (mDaemonLock) {

mOutputStream = socket.getOutputStream();

}

...

mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(

event.getCode(), event.getRawEvent()));

// 收到流数据时,直接发给主线程,通过NetdCallbackReceiver 对象进行回调处理

@Override

public boolean handleMessage(Message msg) {

String event = (String) msg.obj;

try {

if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {

log(String.format(Unhandled event '%s', event));

}

} catch (Exception e) {

loge(Error handling ' + event + ': + e);

}

return true;

}

private LocalSocketAddress determineSocketAddress() {

// If we're testing, set up a socket in a namespace that's accessible to test code.

// In order to ensure that unprivileged apps aren't able to impersonate native daemons on

// production devices, even if said native daemons ill-advisedly pick a socket name that

// starts with __test__, only allow this on debug builds.

if (mSocket.startsWith(__test__) && Build.IS_DEBUGGABLE) {

return new LocalSocketAddress(mSocket);

} else {

return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);

}

}

我们接下来看一下LocalSocket相关的类,了解一下这个socket是如何connect和get的。 LocalSocket*相关的类定义在 frameworks/base/core/java/android/net/ |->LocalSocket.java

|->LocalSocketAddress.java |->LocalSocketImpl.java 这里重点看下LocalSocketImpl类,其中就可以看到大量的native函数了,也就是通过jni完成java到C++的交互,有些人可能会有疑问,既然这里使用jni调用了C++库函数,但是这里没有看到System.loadlibary字眼啊。通过jni的基础我们知道这里java类使用的jni名字应该是android_net_LocalSocket*样子的,那么在android工程代码中也确实存在这个名字的cpp文件,路径是frameworks/base/core/jni/。可以确认我们这里的java层就是调用这里的lib库了,而编译后我们知道这个库名为libandroid_runtime.so。那么这个库在哪里load的呢?下面简要提一下。 我们知道android启动时,第一个进程init在解析init.rc时创建了app_process,app_process在创建zygote进程前首先建立dalvikvm虚拟机环境,初始化android runtime,这里就在C环境下预先加载了libandroid_runtime.so库。如下: frameworks/base/core/jni/AndroidRuntime.cpp

static const RegJNIRec gRegJNI[] = {

REG_JNI(register_android_net_LocalSocketImpl),

了解了库加载的问题后,我们接着看LocalSocketImpl.java中使用的几个重要的函数:

connect()

getInputStream()

getOutputStream()

函数具体内容不具体贴出来,其中可以看到调用了本地方法如read_native(),writeba_native()等。我们就走到native的大门了。打开本地函数文件,看下native中本地函数列表。 frameworks/base/core/jni/android_net_LocalSocketImpl.cpp

static JNINativeMethod gMethods[] = {

/* name, signature, funcPtr */

{getOption_native, (Ljava/io/FileDescriptor;I)I, (void*)socket_getOption},

{setOption_native, (Ljava/io/FileDescriptor;III)V, (void*)socket_setOption},

{connectLocal, (Ljava/io/FileDescriptor;Ljava/lang/String;I)V,

(void*)socket_connect_local},

{bindLocal, (Ljava/io/FileDescriptor;Ljava/lang/String;I)V, (void*)socket_bind_local},

{listen_native, (Ljava/io/FileDescriptor;I)V, (void*)socket_listen},

{accept, (Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;, (void*)socket_accept},

{shutdown, (Ljava/io/FileDescriptor;Z)V, (void*)socket_shutdown},

{available_native, (Ljava/io/FileDescriptor;)I, (void*) socket_available},

{pending_native, (Ljava/io/FileDescriptor;)I, (void*) socket_pending},

{read_native, (Ljava/io/FileDescriptor;)I, (void*) socket_read},

{readba_native, ([BIILjava/io/FileDescriptor;)I, (void*) socket_readba},

{writeba_native, ([BIILjava/io/FileDescriptor;)V, (void*) socket_writeba},

{write_native, (ILjava/io/FileDescriptor;)V, (void*) socket_write},

{getPeerCredentials_native,

(Ljava/io/FileDescriptor;)Landroid/net/Credentials;,

(void*) socket_get_peer_credentials}

//,{getSockName_native, (Ljava/io/FileDescriptor;)Ljava/lang/String;,

//

(void *) socket_getSockName}

};

int register_android_net_LocalSocketImpl(JNIEnv *env){}

相关报道:

最近做了一个neutron集成vyatta的任务,顺便认真学习下neutron的代码,头几行就看到了monkey_patch。首先就从neutron-server的启动脚本开始:[root@controller-3 更多

题意:Given n (1 更多

你可能感兴趣的:(android,ethernet,框架)