美文网首页
Network Service Discovery - mDNS

Network Service Discovery - mDNS

作者: MelanDawn | 来源:发表于2021-11-28 22:00 被阅读0次

    基于 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

    相关文章

      网友评论

          本文标题:Network Service Discovery - mDNS

          本文链接:https://www.haomeiwen.com/subject/toafxrtx.html