Android Says Bonjour

  • Android Says Bonjour

It's a pleasure to continue the Android story for readers in this issue of Programmer Magazine, which begins the Lunar Year of the Snake . When I first arrived, I first wanted to say "hello" to everyone. Interestingly, Android is also very human, since 4.1 , it will say " Bonjour ". But does it speak in an authentic French accent? See below.

A background knowledge introduction

Bonjour means Hello in French . It is Apple 's name for an open, zero-configuration networking standard based on multicast DNS . Devices using Bonjour automatically multicast their own service information in the network and monitor the service information of other devices. The devices are like greeting each other, which is why the technology is named Bonjour . Bonjour makes it easy to find systems and services on a local area network even without a network administrator.

Take a simple example: in a local area network, if you want to perform printing services, you must first know the IP address of the print server. This IP address is generally assigned by someone in the IT department, and then he has to send an email to all the staff to publicize the address. With Bonjour , the print server itself will find an available IP within the local area network according to the zero-configuration network standard and register a print service called " print service " or the like. When a client needs a print service, it will first search for a print server within the network. Since the IP address of the print server is not known , clients can only find printers by names such as "print service" . With the help of Bonjour , the client can finally find the printer registered with the name " print service " and obtain its IP address and port number.

From a Bonjour perspective, the technology mainly solves three problems:

  • Addressing : That is, assign IP to the host . Bonjour 's Addressing processing is relatively simple, that is, each host finds an IP within the optional range of addresses within the network, and then checks whether there are other hosts within the network to use. If the IP is not assigned, it will use this IP .
  • Naming : Naming resolves the correspondence between host names and IP addresses. Bonjour uses Multiple DNS technology, that is, DNS query messages will be sent through UDP multicast. Once a machine in the network finds that the queried machine name is the same as the one set by itself, it will reply to this request. In addition, Bonjour also expands the use of MDNS , that is, in addition to searching for hosts , it also supports searching for services . However, Bonjour 's Naming has a limitation, that is, there cannot be a host or service with the same name within the network .
  • Service Discovery : SD is based on the above Naming work, which enables applications to find services within the network and resolve the IP address and port number corresponding to the service. Once the application obtains the IP address and port number of the service, it can directly establish an interactive relationship with the service.

Bonjour technology has been widely used in Mac OS , Itunes and Iphone . For further promotion, Apple open sourced it through the open source project mdnsresponder . On Windows platform, it will generate a daemon mdnsresponder . On Android platforms (or Linux platforms that support POSIX ) it is a program called mdnsd . However, whether it is mdnsresponder or mdnsd , the application developers only need to use Bonjour 's API to initiate service registration, service query and service resolution requests to them and receive processing results from them.

Below we will introduce the three most used functions in the Bonjour API , which are service registration, service query and service resolution. Understanding the functions of these three functions is also the basis for understanding MDnsSdListener .

To use the Bonjour API you must include the following header files and dynamic libraries and link to:

#include < dns_sd.h > //This header file must be included   // link to this so

In Bonjour , the API for service registration is DNSServiceRegister , the prototype is shown in Figure 1 :

Figure 1 DNSServiceRegister prototype

The function is explained as follows:

  • sdRef : Represents an uninitialized DNSService entity. Its type DNSServiceRef is a pointer. This parameter is finally allocated and initialized by the DNSServiceRegister function.
  • flags : Indicates the conflict handling when there are services with the same name in the network. The default is to modify the service names sequentially. For example, the name of the service to be registered is " printer ", when a duplicate name conflict is detected, it can be renamed " printer(1) ".
  • interfaceIndex : Indicates which network interfaces the service outputs to the host. A value of -1 means native support only, that is, the service is used on the loop interface.
  • name : Indicates the service name, if it is empty, the machine name is used.
  • regtype : Service type, expressed as a string. Bonjour requires the format " _service_name._transport_protocol " , eg " _ftp._tcp " . Currently the transport protocol only supports TCP and UDP .
  • domian and host are generally empty.
  • port indicates the port of the service. If 0 , Bonjour will automatically assign one.
  • The txtLen and txtRecord strings are used to describe the service. Usually set to empty.
  • callBack : Set the callback function. The request result registered by the server will be called back to the client through it.
  • context : context pointer, set by the application.

When the client needs to search for a specific service within the network, it needs to use the DNSServiceBrowser API , the prototype of which is shown in Figure 2 :

Figure 2 DNSServiceBrowser prototype


  • sdref , interfaceIndex , regtype , domain and context have the same meaning as DNSServiceRegister .
  • flags : has no effect in this function.
  • callBack : Callback notification interface for DNSServiceBrowser processing results.

When the client wants to obtain the IP and port number of the specified service, it needs to use the DNSServiceResolve API , whose prototype is shown in Figure 3 :

Figure 3 DNSServiceResolve prototype


  • name , regtype and domain are all obtained from the processing result of the DNSServiceBrowse function .
  • callBack is used to notify DNSServiceResolve of the processing result. This callback function will return the IP address and port number of the service.

The three APIs introduced above are the core APIs of Bonjure . But what about Bonjour in Android ?

Android Says Hello

It's almost certain that Bonjour will need some customization to run on Android . However, this customization is not for mdnsd itself, but for the use of the Bonjour API . The Bonjour architecture of the Android platform can be expressed in Figure 4 :

Figure 4 Android Bonjour Architecture

As can be seen from Figure 4 , Android extends the original Bonjour architecture and changes as follows:

  • The MDnsSdListener object is added to Netd . On the one hand, it communicates with upper-layer objects through sockets , and on the other hand, it communicates with mdnsd through Bonjour API (also Socket -based cross-process communication). From mdnsd's point of view, it is the "people" who understand the Bonjour API the most.
  • Added NsdService to the System_process process . Nsd is an acronym for Network Service Discovery . NsdService communicates with MDnsSdListener located in Netd through socket .
  • App borrows NsdManager API to communicate with NsdService of System_process through Binder technology .

In short, in the Android platform, the application needs to rely on the other three processes ( System_process , Netd , mdnsd ) to enjoy the benefits of Bonjour . However, will such complicated inter-process communication affect efficiency?

The answer is yes. But just like Bonjour 's original intention, it's just a hello to know the existence of services in the network and some simple information. Once the client obtains the IP address and port of the service through Bonjour , the subsequent interaction between the client and the service belongs to the private category (that is, the client directly establishes a connection with the service through the IP address). From this point of view, this loss of efficiency on Android is innocuous.

In addition, the design of the Bonjour architecture on Android has another enlightenment for readers: if a mobile phone manufacturer wants to customize some functions, it is best to have a full understanding of the existing Android architecture first. Only in this way can the functional modules be reasonably integrated into the Android architecture according to their own needs to play their functions more effectively.

Let's take a look at several important members of the Bonjour architecture in Android .

2.1 Introduction to MDnsSdListener

MDnsSdListener acts as a converter in the Android Bonjour architecture:

  • On the one hand it handles requests from NsdService and converts them into a "language" that mdnsd understands through the Bonjour API to drive its work.
  • On the other hand it receives messages from mdnsd and informs them to NsdService .

Figure 5 shows a schematic diagram of the family members of MDnsSdListener .

Figure 5 MDnsSdListener family members

It can be seen from Figure 5 that:

  • The internal class Monitor of MDnsSdListener is used to communicate with the mdnsd process, and it will call the aforementioned Bonjour API .
  • Monitor will create an Element object for each DNSService internally, which is stored in a list through the Monitor 's mHead pointer .
  • Handler is the Command registered by MDnsSdListener .

The following will briefly introduce the running process of MDnsSdListener . Its main work can be divided into three steps:

  • Netd creates an MDnsSdListener object, which will create a Monitor object inside, and the Monitor object will start a thread to communicate with mdnsd and receive requests from Handler .
  • After the NsdService is started, it will send the "start-service" command to the MDnsSdListener .
  • The NsdService responds to the application's request and sends other commands, such as "discovery" , to the MDnsSdListener . Monitor will eventually handle these requests.

Let's first look at the first step. When the MDnsSdListener is constructed, a Monitor object will be created. The code is shown in Figure 6 :

Figure 6 Structure of Monitor

It can be seen from Figure 6 that:

  • The threadStart thread of Monitor will call its run function, which listens for socket information including mCtrlSocketPair by polling . This part of the code belongs to basic Linux socket programming. For most readers, it shouldn't be too difficult.
  • When NsdService sends "start-service" command, Handler 's runCommand will execute Monitor 's startService function.

starService will start mdnsd , the method it uses is quite Android , as shown in Figure 7 :

Figure 7 startService code schematic

In Figure 7 , the MDS_SERVICE_NAME macro represents the string "mdnsd" . Readers who know Android , after reading Figure 7 , can you quickly know how Android starts mdnsd ?

When NsdService sends a service registration request, the serviceRegister function of Handler will be called. The code is shown in Figure 8 :

Figure 8 Schematic diagram of serviceRegister

DNSServiceRegister will send the request to mdnsd for processing, and the processing result will be returned through MDnsSdListenerRegisterCallback , which will eventually pass the information to NsdService through socket for processing.

The introduction of MDnsSdListener is here for now. Interested readers may wish to take a look at the code to deepen their understanding of the usage of the Bonjour API .

2.2 Introduction to NsdService

For all Android Apps , NsdService is the Boss behind it , and its usage (of course, the usage of NsdManager, the encapsulation class of NsdService client API ) is also listed in black and white in the SDK documentation. The internal structure of NsdService can be represented by Figure 9 :

Figure 9 Schematic diagram of the internal structure of NsdService

Figure 9 lists several important members in NsdService , among which:

  • NsdService is derived from INsdManager.stub . This class is also a featured product of Android and is generated by the INsdManager.aidl file.
  • The internal work of NsdService will be driven by NsdStateMachine and three internal state objects ( DefaultState , EnableState , DisableState ). To the author's surprise, the code of the entire NsdService is only about 800 lines. And theoretically, there are no state transitions in NSD . The emergence of state machines makes code understanding relatively difficult. Fortunately , NsdStateMachine has only three states. Readers may wish to take it as an opportunity to learn about the usage of StateMachine in Android . Because it is used in many places in the system. In that code, there are more than three states.
  • NsdService establishes socket communication through NativeDaemonConnector and MDnsSdListener in Netd .
  • The class NativeCallbackReceiver is used to notify NsdService of messages from Netd .
  • Of course, the most important output of NsdService is NsdServiceInfo . It is the representative of Network Service in Android Bonjour . It contains the service name, service type, IP address and port number.

Due to space reasons, this article does not intend to discuss NsdService in detail. Next, this article will introduce NsdChat , a small example of Nsd API usage in the Android SDK .

2.3 NsdChat case introduction

A new NsdChat example has been added to the Android SDK to introduce developers to the use of Nsd in the Android platform . Related documentation is at . The source code of the case is located under the Android4.1 source code root directory /development/samples/training/NsdChat .

This example describes a simple chat program, so it is named NsdChat . The role of Nsd in this example is to register and search for chat services within the network. So, in this example there is an NsdChat process that will register a chat service through the registerService function of NsdService . The relevant code is shown in Figure 10 :

Figure 10 NsdChat registered chat service

It can be seen from Figure 10 that:

  • The Nsd service to be registered by the application will be expressed through the NsdServiceInfo class. Combined with the previous background knowledge, in this NsdServiceInfo , the most important is the port number of the service, the service name (according to Bonjour 's requirements, there cannot be a service with the same name in the network) and the type of the service.
  • Next, the application registers this service through the registerService function of NsdManager . The result of registration is notified through the internal interface class RegistrationListener of NsdManager .

It only makes sense for two people to chat, so another client process running NsdChat will search for the " NsdChat " service inside the network. The relevant code is shown in Figure 11 :

Figure 11  Looking for the " NsdChat " service

It can be seen from Figure 11 that:

  • The application process only needs to call the discoveryServices function of NsdManager and pass the service type to be found. The search results are returned through the NsdManager 's internal interface class DiscoveryListener .

Note that Nsd can only be searched by service type. When there are multiple services of the same service type (in this example, the service type is "_http._tcp." ) in the network, the application also needs to filter according to the information returned by DiscoveryListener . This part of the code is shown in Figure 12 :

Figure 12 DiscoveryListener processing of NsdChat

As can be seen from Figure 12 , the result of discoveryServices is returned through the callback function provided by the DiscoveryListener interface class. Pay attention to the filtering processing of the same type of service in the onServiceFound function (it is worth pointing out that the Android SDK does not make any explanation for the easily neglected place here).

After the client successfully finds the NsdChat service, the next step is to resolve the IP address and port number of the service. This is done through the resolveService function of NsdManager (note the red box in Figure 12 ). The processing result of this function will be returned by another interface class ResolveListener defined by NsdManager .

Through research on NsdChat , readers will find:

  • Overall, the use of NsdManager is not complicated, and the related classes are relatively simple.
  • The only special thing is that its main API is designed to be called asynchronously, which will increase the difficulty of application development. Please read be sure to pay attention to this.

Three summary

This article introduces the implementation of Bonjour in Android . The principle knowledge of Bonjour also invites readers to read . This website is the entry point for basic knowledge of Bonjure , including " About Bonjour ", " Bonjour API Architecture " and other documents.

In addition, Bonjour in Android is mainly to support the Network Service Discovery function. Similar to it is Simple Service Discovery Protocol ( SSDP ) used in UPnP technology . Compared with Bonjour , UPnP not only implements NSD , but also supports the standard SOAP protocol in the subsequent interaction between client and server, which greatly facilitates the implementation of code logic between client and server. Therefore, the author hereby reminds developers that if they want to use the Bonjour technology, they should pay special attention to the fact that Nsd can only simplify the step of service registration and search. In the future, it is necessary to focus on the protocol and implementation of the interaction between the client and the server.

Regarding DLNA, readers can refer to the author's blog PPT at the software conference - DLNA solution introduction.html .

Related: Android Says Bonjour