Network Service Discovery - mDNS

2021-11-28  本文已影响0人  MelanDawn

基于 AOSP master 分支,至少是 Android 12

1. Overview

2. Network Service Discovery Flow

以 discoverService 为例,介绍 Network Service Discovery 调用流程

2.1 NSD Flow in API & Framework

frameworks/base/core/java/android/net/nsd/NsdManager.java

    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
        checkStringNotEmpty(serviceType, "Service type cannot be empty");
        checkProtocol(protocolType);

        NsdServiceInfo s = new NsdServiceInfo();
        s.setServiceType(serviceType);

        int key = putListener(listener, s);
        try {
            mService.discoverServices(key, s);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
    }

frameworks/base/services/core/java/com/android/server/NsdService.java

    private class NsdServiceConnector extends INsdServiceConnector.Stub
            implements IBinder.DeathRecipient  {

        @Override
        public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) {
            mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
                    NsdManager.DISCOVER_SERVICES, 0, listenerKey,
                    new ListenerArgs(this, serviceInfo)));
        }
    }
        class EnabledState extends State {
            @Override
            public boolean processMessage(Message msg) {
                final ClientInfo clientInfo;
                final int id;
                final int clientId = msg.arg2;
                final ListenerArgs args;
                switch (msg.what) {
                    case NsdManager.DISCOVER_SERVICES:
                        args = (ListenerArgs) msg.obj;
                        clientInfo = mClients.get(args.connector);

                        maybeStartDaemon();
                        id = getUniqueId();
                        if (discoverServices(id, args.serviceInfo.getServiceType())) {
                            storeRequestMap(clientId, id, clientInfo, msg.what);
                            clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo);
                        }
                        break;

这里有两个重要方法:

  1. maybeStartDaemon()
  2. discoverServices()

2.1.1 maybeStartDaemon()

frameworks/base/services/core/java/com/android/server/NsdService.java

    private class NsdStateMachine extends StateMachine {

        private void maybeStartDaemon() {
            mDaemon.maybeStart();
            maybeScheduleStop();
        }
    }
    public static class DaemonConnection {
        final NativeDaemonConnector mNativeConnector;
        boolean mIsStarted = false;

        DaemonConnection(NativeCallbackReceiver callback) {
            mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null);
            new Thread(mNativeConnector, MDNS_TAG).start();
        }

        public void maybeStart() {
            if (mIsStarted) {
                return;
            }
            execute("start-service");
            mIsStarted = true;
        }


        public boolean execute(Object... args) {
            try {
                mNativeConnector.execute("mdnssd", args);
            } catch (NativeDaemonConnectorException e) {
                return false;
            }
            return true;
        }

要执行之,首先需要执行 的初始化
// 初始化过程先不分析了,结论是作为 client 端连接一个 socket 到 server端(netd)

  1. 初始化过程出现了 “mdns”,在初始化过程逐步解析为 dev/socket/mdns,最终连接到它;
  2. 命令执行中出现了 “mdnssd”,这是 Network Service Discovery 操作的命令,其他内容作为它的参数;
  3. 此处执行的 “start-service” 便是以 “mdnssd” 为命令,以 “start-service” 作为参数列表

2.1.2 discoverServices()

    private boolean discoverServices(int discoveryId, String serviceType) {
        return mDaemon.execute("discover", discoveryId, serviceType);
    }

与前文分析相同,以 “mdnssd” 为命令,以 “discover”、discoveryId、serviceType 作为参数列表

2.2 NSD Flow in Netd

system/netd/server/main.cpp

int main() {
......
    MDnsSdListener mdnsl;
    if (mdnsl.startListener()) {
        exit(1);
    }
......
}

system/core/libsysutils/src/SocketListener.cpp

int SocketListener::startListener() {
    return startListener(4);
}




int SocketListener::startListener(int backlog) {
......
    if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
        return -1;
    }

    return 0;
}



void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener();
    pthread_exit(nullptr);
    return nullptr;
}



void SocketListener::runListener() {
    while (true) {
......
        for (SocketClient* c : pending) {
            if (!onDataAvailable(c)) {
                release(c, false);
            }
            c->decRef();
        }
    }
}

onDataAvailable() 方法的具体实现在 SocketListener 子类 FrameworkListener 中

system/core/libsysutils/include/sysutils/FrameworkListener.h

class FrameworkListener : public SocketListener {
......
}



bool FrameworkListener::onDataAvailable(SocketClient *c) {
......
    for (i = 0; i < len; i++) {
        if (buffer[i] == '\0') {
            if (mSkipToNextNullByte) {
                mSkipToNextNullByte = false;
            } else {
                dispatchCommand(c, buffer + offset);
            }
            offset = i + 1;
        }
    }
    return true;
}
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
......
    for (auto* c : mCommands) {
        if (!strcmp(argv[0], c->getCommand())) {
            if (c->runCommand(cli, argc, argv)) {

            }
            goto out;
        }
    }
......
}



void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
    mCommands.push_back(cmd);
}

先确定 mCommand 集合里有什么,才能确定具体执行的 runCommand() 方法是什么
system/netd/server/MDnsSdListener.cpp

MDnsSdListener::MDnsSdListener() : FrameworkListener(SOCKET_NAME, true) {
    Monitor *m = new Monitor();
    registerCmd(new Handler(m, this));
}


MDnsSdListener::Handler::Handler(Monitor *m, MDnsSdListener *listener) :
   NetdCommand("mdnssd") {
   mMonitor = m;
   mListener = listener;
}

从以上源码可知,注册的命令是 “mdnssd”,与前文的客户端匹配

具体命令的处理过程如下,前文提到了 discover 和 start-service 两个操作,这里仅分析 discover 命令

int MDnsSdListener::Handler::runCommand(SocketClient *cli,
                                        int argc, char **argv) {
.......
    if (strcmp(cmd, "discover") == 0) {
        int requestId = strtol(argv[2], nullptr, 10);
        char *serviceType = argv[3];

        discover(cli, nullptr, serviceType, nullptr, requestId, 0);
    } else if (strcmp(cmd, "start-service") == 0) {
        if (mMonitor->startService()) {
            cli->sendMsg(ResponseCode::CommandOkay, "Service Started", false);
        } else {
            cli->sendMsg(ResponseCode::ServiceStartFailed, "Service already running", false);
        }
    }
......
}
void MDnsSdListener::Handler::discover(SocketClient *cli,
        const char *iface,
        const char *regType,
        const char *domain,
        const int requestId,
        const int requestFlags) {
......
    DNSServiceErrorType result = DNSServiceBrowse(ref, nativeFlags, interfaceInt, regType,
            domain, &MDnsSdListenerDiscoverCallback, context);
......
}

2.3 NSD Flow in mDNSResponder

external/mdnsresponder/mDNSShared/dnssd_clientstub.c

DNSServiceErrorType DNSSD_API DNSServiceBrowse
    (
    DNSServiceRef         *sdRef,
    DNSServiceFlags        flags,
    uint32_t               interfaceIndex,
    const char            *regtype,
    const char            *domain,
    DNSServiceBrowseReply  callBack,
    void                  *context
    )
    {
}
mDNSResponder Architecture.png
上一篇下一篇

猜你喜欢

热点阅读