一 引言
在上一篇文章,我们从上层APP出发,通过以太网的使能来分析了以太网框架中,上层指令如何传递到底层。这篇文章,我们将通过网口注册的流程来分析,以太网框架中,底层事件状态是如何上报给上层。图1-1所示为网口注册的整体流程图。
图1-1 网口注册整体流程图
二 Netd事件上报流程
从上一节图1-1可以看出,Netd是通过SocketListener来监听底层的Uevent的事件上报。在分析Netd事件上报之前,有必要先将Netd中相关的类的关系梳理一下,具体类图如下2-1所示:
图2-1 Netd相关类图关系
从Netd的类图关系看,主要有4个类,其主要作用如下:
- SocketListener : 这是Native层获取底层Uevent的公用接口类,Android其他一些模块,例如vold模块,也通过该Listener来监听底层Uevent事件。监听到事件后,通过onDataAvailable来处理底层上报的数据;
- NetlinkListener:该类继承自SocketListener。在onDataAvailable函数中调用onEvent继续封装底层的事件;
- NetlinkHandler:该类继承自NetlinkListener。在onEvent中继续封装处理底层事件,并通过上层注册的监听对象,将该状态上报给上层。
- NetlinkManager:其内部维护了几个NetinkHandler引用对象,以及一个SocketListener引用对象,来管理socket的通信,包括socket的创建,以及释放等等。
Netd在启动时候,会创建NetlinkManager引用对象,并且创建NetlinkHandler的引用对象,并且调用其start来启动监听,最后会调用到SocketListener的runListener函数中,来实时监听底层Uevent事件上报。
//SocketListener.cpp
void SocketListener::runListener() {
while (true) {
std::vector<pollfd> fds;
pthread_mutex_lock(&mClientsLock);
fds.reserve(2 + mClients.size());
fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN});
if (mListen) fds.push_back({.fd = mSock, .events = POLLIN});
for (auto pair : mClients) {
// NB: calling out to an other object with mClientsLock held (safe)
const int fd = pair.second->getSocket();
if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first);
fds.push_back({.fd = fd, .events = POLLIN});
}
pthread_mutex_unlock(&mClientsLock);
SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName);
int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1));
if (rc < 0) {
SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen);
sleep(1);
continue;
}
if (fds[0].revents & (POLLIN | POLLERR)) {
char c = CtrlPipe_Shutdown;
TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
if (c == CtrlPipe_Shutdown) {
break;
}
continue;
}
if (mListen && (fds[1].revents & (POLLIN | POLLERR))) {
int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
if (c < 0) {
SLOGE("accept failed (%s)", strerror(errno));
sleep(1);
continue;
}
pthread_mutex_lock(&mClientsLock);
mClients[c] = new SocketClient(c, true, mUseCmdNum);
pthread_mutex_unlock(&mClientsLock);
}
// Add all active clients to the pending list first, so we can release
// the lock before invoking the callbacks.
std::vector<SocketClient*> pending;
pthread_mutex_lock(&mClientsLock);
const int size = fds.size();
for (int i = mListen ? 2 : 1; i < size; ++i) {
const struct pollfd& p = fds[i];
if (p.revents & (POLLIN | POLLERR)) {
auto it = mClients.find(p.fd);
if (it == mClients.end()) {
SLOGE("fd vanished: %d", p.fd);
continue;
}
SocketClient* c = it->second;
pending.push_back(c);
c->incRef();
}
}
pthread_mutex_unlock(&mClientsLock);
for (SocketClient* c : pending) {
// Process it, if false is returned, remove from the map
SLOGV("processing fd %d", c->getSocket());
//通过onDataAvailable函数处理底层事件的上报
if (!onDataAvailable(c)) {
release(c, false);
}
c->decRef();
}
}
}
在runListener中是一个死循环,实时监听底层的Uevent事件。在接收到底层事件上报后,最终调用onDataAvailable处理,真正实现是在子类NetLinkListener中,具体代码如下:
//NetlinkListener.cpp
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
int socket = cli->getSocket();
ssize_t count;
uid_t uid = -1;
bool require_group = true;
if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) {
require_group = false;
}
//通过uevent_kernel_recv获取底层Uevent事件,并将其存储到mBuffer中
count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,
mBuffer, sizeof(mBuffer), require_group, &uid));
if (count < 0) {
SLOGE("recvmsg failed (%s)", strerror(errno));
return false;
}
//创建NetlinkEvent对象,并且解析后,最终调用onEvent做进一步处理
NetlinkEvent *evt = new NetlinkEvent();
if (evt->decode(mBuffer, count, mFormat)) {
onEvent(evt);
} else if (mFormat != NETLINK_FORMAT_BINARY) {
// Don't complain if parseBinaryNetlinkMessage returns false. That can
// just mean that the buffer contained no messages we're interested in.
SLOGE("Error decoding NetlinkEvent");
}
delete evt;
return true;
}
在NetLinkListener中的onDataAvailable方法中,主要做了以下三件事:
- 通过uevent_kernel_recv获取底层的Uevent事件的上报,并将其存储到mBuffer中;
- 创建NetlinkEvent对象,并调用decode函数,将mBuffer中的数据风封装到NetlinkEvent中;
- 最终调用子类的onEvent继续处理;
bool NetlinkEvent::decode(char *buffer, int size, int format) {
if (format == NetlinkListener::NETLINK_FORMAT_BINARY
|| format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) {
return parseBinaryNetlinkMessage(buffer, size);
} else {
return parseAsciiNetlinkMessage(buffer, size);
}
}
在decode函数中,根据底层上报的是二进制数据做不通的处理,如果是二进制数据,则调用parseBinaryNetlinkMessage函数处理;否则调用parseAsciiNetlinkMessage函数处理。二进制主要是路由等信息的上报,此处我们重点关注非二进制的数据上报。
bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
const char *s = buffer;
const char *end;
int param_idx = 0;
int first = 1;
if (size == 0)
return false;
/* Ensure the buffer is zero-terminated, the code below depends on this */
buffer[size-1] = '\0';
end = s + size;
while (s < end) {
if (first) {
const char *p;
/* buffer is 0-terminated, no need to check p < end */
for (p = s; *p != '@'; p++) {
if (!*p) { /* no '@', should not happen */
return false;
}
}
mPath = strdup(p+1);
first = 0;
} else {
const char* a;
//解析ACTION属性并将其存储到NetlinkEvent的mAction中
if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != nullptr) {
if (!strcmp(a, "add"))
//如果是网口的注册,此处动作是add
mAction = Action::kAdd;
else if (!strcmp(a, "remove"))
mAction = Action::kRemove;
else if (!strcmp(a, "change"))
mAction = Action::kChange;
} else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != nullptr) {
mSeq = atoi(a);
} else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != nullptr) {
mSubsystem = strdup(a);
} else if (param_idx < NL_PARAMS_MAX) {
mParams[param_idx++] = strdup(s);
}
}
s += strlen(s) + 1;
}
return true;
}
在parseAsciiNetlinkMessage中,主要解析ACTION=参数,并将其存储到NetlinkEvent的mAction中。下面我们直接看NetlinkListener的子类NetlinkHandler的onEvent中处理,我们直接看代码:
//NetlinkHandler.cpp
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
if (!subsys) {
ALOGW("No subsystem found in netlink event");
return;
}
//解析net参数,再根据action的不同做不同的处理
if (!strcmp(subsys, "net")) {
NetlinkEvent::Action action = evt->getAction();
const char *iface = evt->findParam("INTERFACE");
if ((action == NetlinkEvent::Action::kAdd) ||
(action == NetlinkEvent::Action::kLinkUp) ||
(action == NetlinkEvent::Action::kLinkDown)) {
const char *ifIndex = evt->findParam("IFINDEX");
long ifaceIndex = parseIfIndex(ifIndex);
if (ifaceIndex) {
//先根据iface做addInterface处理
gCtls->trafficCtrl.addInterface(iface, ifaceIndex);
} else {
ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
}
}
//通知上层,底层状态发生变化
if (action == NetlinkEvent::Action::kAdd) {
notifyInterfaceAdded(iface);
} else if (action == NetlinkEvent::Action::kRemove) {
......
}
}
NetlinkHandler的onEvent函数主要完成两件事:
- 通过trafficCtrl的addInterface函数创建注册的interface;
- 根据Action,调用notifyInterfaceAdded函数,通知上层状态的变化;
我们直接看notifyInterfaceAdded函数的实现:
void NetlinkHandler::notifyInterfaceAdded(const std::string& ifName) {
LOG_EVENT_FUNC(BINDER_RETRY, onInterfaceAdded, ifName);
}
//宏函数定义,获取每个注册NetdUnsolicitedListener,然后调用其函数onInterfaceAdded
#define LOG_EVENT_FUNC(retry, func, ...) \
do { \
const auto listenerMap = gCtls->eventReporter.getNetdUnsolicitedEventListenerMap(); \
for (auto& listener : listenerMap) { \
auto entry = gUnsolicitedLog.newEntry().function(#func).args(__VA_ARGS__); \
if (retry(listener.first->func(__VA_ARGS__))) { \
gUnsolicitedLog.log(entry.withAutomaticDuration()); \
} \
} \
} while (0)
这里通过宏函数,获取每个注册的NetdUnsolicitedListener,然后调用对应的函数,此处为onInterfaceAdded。在Android以太网服务启动源码分析中,我们知道在NetworkManagementService的connectNativeService中注册了NetdUnsolicitedListener。所以下面将会进入framework层的处理。这里我们最后在分析一下getNetdUnsolicitedEventListenerMap的注册和获取。
EventReporter::UnsolListenerMap EventReporter::getNetdUnsolicitedEventListenerMap() const {
std::lock_guard lock(mUnsolicitedMutex);
return mUnsolListenerMap;
}
//上层调用NetdUnsolicitedListener的注册,最终会走到这里,
//并将注册的Listener添加到mUnsolListenerMap中
void EventReporter::registerUnsolEventListener(
const android::sp<INetdUnsolicitedEventListener>& listener) {
std::lock_guard lock(mUnsolicitedMutex);
// Create the death listener.
class DeathRecipient : public android::IBinder::DeathRecipient {
public:
DeathRecipient(EventReporter* eventReporter,
android::sp<INetdUnsolicitedEventListener> listener)
: mEventReporter(eventReporter), mListener(std::move(listener)) {}
~DeathRecipient() override = default;
void binderDied(const android::wp<android::IBinder>& /* who */) override {
mEventReporter->unregisterUnsolEventListener(mListener);
}
private:
EventReporter* mEventReporter;
android::sp<INetdUnsolicitedEventListener> mListener;
};
android::sp<android::IBinder::DeathRecipient> deathRecipient =
new DeathRecipient(this, listener);
android::IInterface::asBinder(listener)->linkToDeath(deathRecipient);
// TODO: Consider to use remote binder address as registering key
mUnsolListenerMap.insert({listener, deathRecipient});
}
至此,Netd的流程就分析完了,下面我们来分析Framework层的处理。
三 Framework处理事件上报流程
上一节我们知道,最后底层的事件,回调到NetworkManagementService的NetdUnsolicitedEventListener中。我们直接看NetdUnsolicitedEventListener的回调函数:
//NetworkManagementService.java
private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
......
@Override
public void onInterfaceAdded(String ifName) throws RemoteException {
mDaemonHandler.post(() -> notifyInterfaceAdded(ifName));
}
@Override
public void onInterfaceRemoved(String ifName) throws RemoteException {
mDaemonHandler.post(() -> notifyInterfaceRemoved(ifName));
}
......
}
private void notifyInterfaceAdded(String iface) {
Slog.d(TAG, "notifyInterfaceAdded iface: " + iface);
invokeForAllObservers(o -> o.interfaceAdded(iface));
}
上层回调到NetdUnsolicitedEventListener的onInterfaceAdded方法中,最后调用notifyInterfaceAdded方法做处理。该方法很简单直接调用invokeForAllObservers通知注册的Observers。通过Android以太网服务启动源码分析可以知道,EthernetTracker中注册了该Observer,我们直接看该回调。
//EthernetTracker.java
private class InterfaceObserver extends BaseNetworkObserver {
@Override
public void interfaceAdded(String iface) {
mHandler.post(() -> maybeTrackInterface(iface));
}
}
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) {
//更新ip Config
updateIpConfiguration(iface, mIpConfigForDefaultInterface);
mIpConfigForDefaultInterface = null;
}
//根据iface,调用addInterface创建interface
addInterface(iface);
}
EthernetTracker中主要做了以下两件事
- 首先更新 ip config的,这个和静态ip相关;
- 根据iface,调用addInterface创建interface
private void addInterface(String iface) {
InterfaceConfiguration config = null;
// Bring up the interface so we get link status indications.
try {
//调用NetworkManagementService的setInterfaceUp使能interface
mNMService.setInterfaceUp(iface);
//从Netd获取config信息,主要通过该config获取mac地址
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);
}
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);
//调用EthernetNetworkFactory的addInterface增加网络注册
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")) {
//通知app注册的listener,更新interface的状态
updateInterfaceState(iface, true);
}
}
addInterface主要完成以下几件事:
- 调用NMService的setInterfaceUp方法,使能以外网功能;
- 调用NMService的getInterfaceConfig获取interface config,并通过其获取硬件mac地址;
- 通过iface从mNetworkCapabilities获取网路能力的类——NetworkCapabilities,如果没有,则通过硬件mac地址获取NetworkCapabilities;如果还没有,则创建默认的NetworkCapabilities;
- 调用EthernetNetworkFactory的addInterface增加网络注册,更新网络能力,ip配合等信息;
- 通知app注册的Listener,更新interface的状态。
private void updateInterfaceState(String iface, boolean up) {
//调用updateInterfaceLinkState更新连接状态,最终更新到ConnectService中通知网络状态的改变
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;
}
}
//最终调用listener的onAvailabilityChanged方法,更新状态
mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up);
} catch (RemoteException e) {
// Do nothing here.
}
}
mListeners.finishBroadcast();
}
}
EthernetManager注册了该Listener,我们直接看EthernetManager的处理:
//EthernetManager。java
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//发送MSG_AVAILABILITY_CHANGED消息,回调对应listener的onAvailabilityChanged
if (msg.what == MSG_AVAILABILITY_CHANGED) {
boolean isAvailable = (msg.arg1 == 1);
for (Listener listener : mListeners) {
listener.onAvailabilityChanged((String) msg.obj, isAvailable);
}
}
}
};
//收到底层的状态改变后,回调到此处,并且通过handler,发送MSG_AVAILABILITY_CHANGED消息处理
private final IEthernetServiceListener.Stub mServiceListener =
new IEthernetServiceListener.Stub() {
@Override
public void onAvailabilityChanged(String iface, boolean isAvailable) {
mHandler.obtainMessage(
MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, iface).sendToTarget();
}
};
//应用层通过addListener,添加Listener,最后通过onAvailabilityChanged回调,网线插拔的动作
public void addListener(Listener listener) {
mListeners.add(listener);
if (mListeners.size() == 1) {
try {
mService.addListener(mServiceListener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
在EthernetManager中,当EthernetTracker中有底层状态信息改变的时候,会回调到IEthernetServiceListener的onAvailabilityChanged中。通过Handler发送MSG_AVAILABILITY_CHANGED消息,并且循环回调每个Listener的onAvailabilityChanged中,而Listener是通过应用调用addListener注册的。
四 总结
至此,我们以太网框架源码分析的系列就结束了,其中有很多我们需要关注细小知识点。我们分析了以太网服务的启动,以及底层和上层之间的消息通信。有分析不到位的,欢迎大家一块讨论。敬请期待后面其他模块的源码分析。