FileDocCategorySizeDatePackage
NsdManager.javaAPI DocAndroid 5.1 API26828Thu Mar 12 22:22:10 GMT 2015android.net.nsd

NsdManager

public final class NsdManager extends Object
The Network Service Discovery Manager class provides the API to discover services on a network. As an example, if device A and device B are connected over a Wi-Fi network, a game registered on device A can be discovered by a game on device B. Another example use case is an application discovering printers on the network.

The API currently supports DNS based service discovery and discovery is currently limited to a local network over Multicast DNS. DNS service discovery is described at http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt

The API is asynchronous and responses to requests from an application are on listener callbacks on a seperate thread.

There are three main operations the API supports - registration, discovery and resolution.

Application start
|
|
| onServiceRegistered()
Register any local services /
to be advertised with \
registerService() onRegistrationFailed()
|
|
discoverServices()
|
Maintain a list to track
discovered services
|
|--------->
| |
| onServiceFound()
| |
| add service to list
| |
|<----------
|
|--------->
| |
| onServiceLost()
| |
| remove service from list
| |
|<----------
|
|
| Connect to a service
| from list ?
|
resolveService()
|
onServiceResolved()
|
Establish connection to service
with the host and port information

An application that needs to advertise itself over a network for other applications to discover it can do so with a call to {@link #registerService}. If Example is a http based application that can provide HTML data to peer services, it can register a name "Example" with service type "_http._tcp". A successful registration is notified with a callback to {@link RegistrationListener#onServiceRegistered} and a failure to register is notified over {@link RegistrationListener#onRegistrationFailed}

A peer application looking for http services can initiate a discovery for "_http._tcp" with a call to {@link #discoverServices}. A service found is notified with a callback to {@link DiscoveryListener#onServiceFound} and a service lost is notified on {@link DiscoveryListener#onServiceLost}.

Once the peer application discovers the "Example" http srevice, and needs to receive data from the "Example" application, it can initiate a resolve with {@link #resolveService} to resolve the host and port details for the purpose of establishing a connection. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified on {@link ResolveListener#onResolveFailed}. Applications can reserve for a service type at http://www.iana.org/form/ports-service. Existing services can be found at http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml Get an instance of this class by calling {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.NSD_SERVICE)}. {@see NsdServiceInfo}

Fields Summary
private static final String
TAG
INsdManager
mService
public static final String
ACTION_NSD_STATE_CHANGED
Broadcast intent action to indicate whether network service discovery is enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state information as int.
public static final String
EXTRA_NSD_STATE
The lookup key for an int that indicates whether network service discovery is enabled or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
public static final int
NSD_STATE_DISABLED
Network service discovery is disabled
public static final int
NSD_STATE_ENABLED
Network service discovery is enabled
private static final int
BASE
public static final int
DISCOVER_SERVICES
public static final int
DISCOVER_SERVICES_STARTED
public static final int
DISCOVER_SERVICES_FAILED
public static final int
SERVICE_FOUND
public static final int
SERVICE_LOST
public static final int
STOP_DISCOVERY
public static final int
STOP_DISCOVERY_FAILED
public static final int
STOP_DISCOVERY_SUCCEEDED
public static final int
REGISTER_SERVICE
public static final int
REGISTER_SERVICE_FAILED
public static final int
REGISTER_SERVICE_SUCCEEDED
public static final int
UNREGISTER_SERVICE
public static final int
UNREGISTER_SERVICE_FAILED
public static final int
UNREGISTER_SERVICE_SUCCEEDED
public static final int
RESOLVE_SERVICE
public static final int
RESOLVE_SERVICE_FAILED
public static final int
RESOLVE_SERVICE_SUCCEEDED
public static final int
ENABLE
public static final int
DISABLE
public static final int
NATIVE_DAEMON_EVENT
public static final int
PROTOCOL_DNS_SD
Dns based service discovery protocol
private android.content.Context
mContext
private static final int
INVALID_LISTENER_KEY
private static final int
BUSY_LISTENER_KEY
private int
mListenerKey
private final android.util.SparseArray
mListenerMap
private final android.util.SparseArray
mServiceMap
private final Object
mMapLock
private final com.android.internal.util.AsyncChannel
mAsyncChannel
private ServiceHandler
mHandler
private final CountDownLatch
mConnected
public static final int
FAILURE_INTERNAL_ERROR
Failures are passed with {@link RegistrationListener#onRegistrationFailed}, {@link RegistrationListener#onUnregistrationFailed}, {@link DiscoveryListener#onStartDiscoveryFailed}, {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}. Indicates that the operation failed due to an internal error.
public static final int
FAILURE_ALREADY_ACTIVE
Indicates that the operation failed because it is already active.
public static final int
FAILURE_MAX_LIMIT
Indicates that the operation failed because the maximum outstanding requests from the applications have reached.
Constructors Summary
public NsdManager(android.content.Context context, INsdManager service)
Create a new Nsd instance. Applications use {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}.

param
service the Binder interface
hide
- hide this because it takes in a parameter of type INsdManager, which is a system private class.


                                                
         
        mService = service;
        mContext = context;
        init();
    
Methods Summary
public voiddiscoverServices(java.lang.String serviceType, int protocolType, android.net.nsd.NsdManager$DiscoveryListener listener)
Initiate service discovery to browse for instances of a service type. Service discovery consumes network bandwidth and will continue until the application calls {@link #stopServiceDiscovery}.

The function call immediately returns after sending a request to start service discovery to the framework. The application is notified of a success to initiate discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure through {@link DiscoveryListener#onStartDiscoveryFailed}.

Upon successful start, application is notified when a service is found with {@link DiscoveryListener#onServiceFound} or when a service is lost with {@link DiscoveryListener#onServiceLost}.

Upon failure to start, service discovery is not active and application does not need to invoke {@link #stopServiceDiscovery}

The application should call {@link #stopServiceDiscovery} when discovery of this service type is no longer required, and/or whenever the application is paused or stopped.

param
serviceType The service type being discovered. Examples include "_http._tcp" for http services or "_ipp._tcp" for printers
param
protocolType The service discovery protocol
param
listener The listener notifies of a successful discovery and is used to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. Cannot be null. Cannot be in use for an active service discovery.

        if (listener == null) {
            throw new IllegalArgumentException("listener cannot be null");
        }
        if (TextUtils.isEmpty(serviceType)) {
            throw new IllegalArgumentException("Service type cannot be empty");
        }

        if (protocolType != PROTOCOL_DNS_SD) {
            throw new IllegalArgumentException("Unsupported protocol");
        }

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

        int key = putListener(listener, s);
        if (key == BUSY_LISTENER_KEY) {
            throw new IllegalArgumentException("listener already in use");
        }

        mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s);
    
private java.lang.ObjectgetListener(int key)

        if (key == INVALID_LISTENER_KEY) return null;
        synchronized (mMapLock) {
            return mListenerMap.get(key);
        }
    
private intgetListenerKey(java.lang.Object listener)

        synchronized (mMapLock) {
            int valueIndex = mListenerMap.indexOfValue(listener);
            if (valueIndex != -1) {
                return mListenerMap.keyAt(valueIndex);
            }
        }
        return INVALID_LISTENER_KEY;
    
private android.os.MessengergetMessenger()
Get a reference to NetworkService handler. This is used to establish an AsyncChannel communication with the service

return
Messenger pointing to the NetworkService handler

        try {
            return mService.getMessenger();
        } catch (RemoteException e) {
            return null;
        }
    
private NsdServiceInfogetNsdService(int key)

        synchronized (mMapLock) {
            return mServiceMap.get(key);
        }
    
private java.lang.StringgetNsdServiceInfoType(NsdServiceInfo s)

        if (s == null) return "?";
        return s.getServiceType();
    
private voidinit()
Initialize AsyncChannel

        final Messenger messenger = getMessenger();
        if (messenger == null) throw new RuntimeException("Failed to initialize");
        HandlerThread t = new HandlerThread("NsdManager");
        t.start();
        mHandler = new ServiceHandler(t.getLooper());
        mAsyncChannel.connect(mContext, mHandler, messenger);
        try {
            mConnected.await();
        } catch (InterruptedException e) {
            Log.e(TAG, "interrupted wait at init");
        }
    
private intputListener(java.lang.Object listener, NsdServiceInfo s)

        if (listener == null) return INVALID_LISTENER_KEY;
        int key;
        synchronized (mMapLock) {
            int valueIndex = mListenerMap.indexOfValue(listener);
            if (valueIndex != -1) {
                return BUSY_LISTENER_KEY;
            }
            do {
                key = mListenerKey++;
            } while (key == INVALID_LISTENER_KEY);
            mListenerMap.put(key, listener);
            mServiceMap.put(key, s);
        }
        return key;
    
public voidregisterService(NsdServiceInfo serviceInfo, int protocolType, android.net.nsd.NsdManager$RegistrationListener listener)
Register a service to be discovered by other services.

The function call immediately returns after sending a request to register service to the framework. The application is notified of a successful registration through the callback {@link RegistrationListener#onServiceRegistered} or a failure through {@link RegistrationListener#onRegistrationFailed}.

The application should call {@link #unregisterService} when the service registration is no longer required, and/or whenever the application is stopped.

param
serviceInfo The service being registered
param
protocolType The service discovery protocol
param
listener The listener notifies of a successful registration and is used to unregister this service through a call on {@link #unregisterService}. Cannot be null. Cannot be in use for an active service registration.

        if (TextUtils.isEmpty(serviceInfo.getServiceName()) ||
                TextUtils.isEmpty(serviceInfo.getServiceType())) {
            throw new IllegalArgumentException("Service name or type cannot be empty");
        }
        if (serviceInfo.getPort() <= 0) {
            throw new IllegalArgumentException("Invalid port number");
        }
        if (listener == null) {
            throw new IllegalArgumentException("listener cannot be null");
        }
        if (protocolType != PROTOCOL_DNS_SD) {
            throw new IllegalArgumentException("Unsupported protocol");
        }
        int key = putListener(listener, serviceInfo);
        if (key == BUSY_LISTENER_KEY) {
            throw new IllegalArgumentException("listener already in use");
        }
        mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo);
    
private voidremoveListener(int key)

        if (key == INVALID_LISTENER_KEY) return;
        synchronized (mMapLock) {
            mListenerMap.remove(key);
            mServiceMap.remove(key);
        }
    
public voidresolveService(NsdServiceInfo serviceInfo, android.net.nsd.NsdManager$ResolveListener listener)
Resolve a discovered service. An application can resolve a service right before establishing a connection to fetch the IP and port details on which to setup the connection.

param
serviceInfo service to be resolved
param
listener to receive callback upon success or failure. Cannot be null. Cannot be in use for an active service resolution.

        if (TextUtils.isEmpty(serviceInfo.getServiceName()) ||
                TextUtils.isEmpty(serviceInfo.getServiceType())) {
            throw new IllegalArgumentException("Service name or type cannot be empty");
        }
        if (listener == null) {
            throw new IllegalArgumentException("listener cannot be null");
        }

        int key = putListener(listener, serviceInfo);

        if (key == BUSY_LISTENER_KEY) {
            throw new IllegalArgumentException("listener already in use");
        }
        mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo);
    
public voidsetEnabled(boolean enabled)
Internal use only @hide

        try {
            mService.setEnabled(enabled);
        } catch (RemoteException e) { }
    
public voidstopServiceDiscovery(android.net.nsd.NsdManager$DiscoveryListener listener)
Stop service discovery initiated with {@link #discoverServices}. An active service discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} and it stays active until the application invokes a stop service discovery. A successful stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}.

Upon failure to stop service discovery, application is notified through {@link DiscoveryListener#onStopDiscoveryFailed}.

param
listener This should be the listener object that was passed to {@link #discoverServices}. It identifies the discovery that should be stopped and notifies of a successful or unsuccessful stop. In API versions 20 and above, the listener object may be used for another service discovery once the callback has been called. In API versions <= 19, there is no entirely reliable way to know when a listener may be re-used, and a new listener should be created for each service discovery request.

        int id = getListenerKey(listener);
        if (id == INVALID_LISTENER_KEY) {
            throw new IllegalArgumentException("service discovery not active on listener");
        }
        if (listener == null) {
            throw new IllegalArgumentException("listener cannot be null");
        }
        mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id);
    
public voidunregisterService(android.net.nsd.NsdManager$RegistrationListener listener)
Unregister a service registered through {@link #registerService}. A successful unregister is notified to the application with a call to {@link RegistrationListener#onServiceUnregistered}.

param
listener This should be the listener object that was passed to {@link #registerService}. It identifies the service that should be unregistered and notifies of a successful or unsuccessful unregistration via the listener callbacks. In API versions 20 and above, the listener object may be used for another service registration once the callback has been called. In API versions <= 19, there is no entirely reliable way to know when a listener may be re-used, and a new listener should be created for each service registration request.

        int id = getListenerKey(listener);
        if (id == INVALID_LISTENER_KEY) {
            throw new IllegalArgumentException("listener not registered");
        }
        if (listener == null) {
            throw new IllegalArgumentException("listener cannot be null");
        }
        mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id);