summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIrfan Sheriff <isheriff@google.com>2012-04-04 12:34:52 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-04-04 12:34:52 -0700
commit689b741abc93a3b44d7a39e9b138162bad330f23 (patch)
tree8d5e09964b44a0e7e6c72eea43018eff1377dcd0
parent271cb5c0d41910a20fe47283e401420635f5e423 (diff)
parent7d024d372431effc87168afdc7cbe387680c4935 (diff)
downloadframeworks_base-689b741abc93a3b44d7a39e9b138162bad330f23.zip
frameworks_base-689b741abc93a3b44d7a39e9b138162bad330f23.tar.gz
frameworks_base-689b741abc93a3b44d7a39e9b138162bad330f23.tar.bz2
Merge "Add initial framework for DNS service discovery"
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/app/ContextImpl.java10
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/net/nsd/DnsSdTxtRecord.java554
-rw-r--r--core/java/android/net/nsd/INsdManager.aidl29
-rw-r--r--core/java/android/net/nsd/NetworkServiceInfo.java32
-rw-r--r--core/java/android/net/nsd/NsdManager.java394
-rw-r--r--core/java/com/android/internal/util/Protocol.java2
-rw-r--r--services/java/com/android/server/NsdService.java269
-rw-r--r--services/java/com/android/server/SystemServer.java10
10 files changed, 1043 insertions, 270 deletions
diff --git a/Android.mk b/Android.mk
index 5879bb5..f65f9e4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -117,6 +117,7 @@ LOCAL_SRC_FILES += \
core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
core/java/android/net/INetworkStatsService.aidl \
+ core/java/android/net/nsd/INsdManager.aidl \
core/java/android/nfc/INdefPushCallback.aidl \
core/java/android/nfc/INfcAdapter.aidl \
core/java/android/nfc/INfcAdapterExtras.aidl \
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d758eca..5ffceb3 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -59,6 +59,8 @@ import android.net.NetworkPolicyManager;
import android.net.ThrottleManager;
import android.net.IThrottleManager;
import android.net.Uri;
+import android.net.nsd.INsdManager;
+import android.net.nsd.NsdManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.IWifiP2pManager;
@@ -372,6 +374,14 @@ class ContextImpl extends Context {
ctx.mMainThread.getHandler());
}});
+ registerService(NSD_SERVICE, new ServiceFetcher() {
+ @Override
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(NSD_SERVICE);
+ INsdManager service = INsdManager.Stub.asInterface(b);
+ return new NsdManager(service);
+ }});
+
// Note: this was previously cached in a static variable, but
// constructed using mMainThread.getHandler(), so converting
// it to be a regular Context-cached service...
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2902504..98ed117 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1769,6 +1769,18 @@ public abstract class Context {
public static final String WIFI_P2P_SERVICE = "wifip2p";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.net.NsdManager} for handling management of network service
+ * discovery
+ *
+ * @hide
+ * @see #getSystemService
+ * @see android.net.NsdManager
+ */
+ public static final String NSD_SERVICE = "servicediscovery";
+
+
+ /**
* Use with {@link #getSystemService} to retrieve a
* {@link android.media.AudioManager} for handling management of volume,
* ringer modes and audio routing.
diff --git a/core/java/android/net/nsd/DnsSdTxtRecord.java b/core/java/android/net/nsd/DnsSdTxtRecord.java
index 4e016b9..6d4342c 100644
--- a/core/java/android/net/nsd/DnsSdTxtRecord.java
+++ b/core/java/android/net/nsd/DnsSdTxtRecord.java
@@ -14,276 +14,292 @@
* See the License for the specific language governing permissions and
* limitations under the License.
- To do:
- - implement remove()
- - fix set() to replace existing values
+ To do:
+ - implement remove()
+ - fix set() to replace existing values
*/
+package android.net.nsd;
-package com.apple.dnssd;
-
-
-/**
- Object used to construct and parse DNS-SD format TXT records.
- For more info see <a href="http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt">DNS-Based Service Discovery</a>, section 6.
-*/
-
-public class TXTRecord
-{
- /*
- DNS-SD specifies that a TXT record corresponding to an SRV record consist of
- a packed array of bytes, each preceded by a length byte. Each string
- is an attribute-value pair.
-
- The TXTRecord object stores the entire TXT data as a single byte array, traversing it
- as need be to implement its various methods.
- */
-
- static final protected byte kAttrSep = '=';
-
- protected byte[] fBytes;
-
- /** Constructs a new, empty TXT record. */
- public TXTRecord()
- { fBytes = new byte[0]; }
-
- /** Constructs a new TXT record from a byte array in the standard format. */
- public TXTRecord( byte[] initBytes)
- { fBytes = (byte[]) initBytes.clone(); }
-
- /** Set a key/value pair in the TXT record. Setting an existing key will replace its value.<P>
- @param key
- The key name. Must be ASCII, with no '=' characters.
- <P>
- @param value
- Value to be encoded into bytes using the default platform character set.
- */
- public void set( String key, String value)
- {
- byte[] valBytes = (value != null) ? value.getBytes() : null;
- this.set( key, valBytes);
- }
-
- /** Set a key/value pair in the TXT record. Setting an existing key will replace its value.<P>
- @param key
- The key name. Must be ASCII, with no '=' characters.
- <P>
- @param value
- Binary representation of the value.
- */
- public void set( String key, byte[] value)
- {
- byte[] keyBytes;
- int valLen = (value != null) ? value.length : 0;
-
- try {
- keyBytes = key.getBytes( "US-ASCII");
- }
- catch ( java.io.UnsupportedEncodingException uee) {
- throw new IllegalArgumentException();
- }
-
- for ( int i=0; i < keyBytes.length; i++)
- if ( keyBytes[i] == '=')
- throw new IllegalArgumentException();
-
- if ( keyBytes.length + valLen >= 255)
- throw new ArrayIndexOutOfBoundsException();
-
- int prevLoc = this.remove( key);
- if ( prevLoc == -1)
- prevLoc = this.size();
-
- this.insert( keyBytes, value, prevLoc);
- }
-
- protected void insert( byte[] keyBytes, byte[] value, int index)
- // Insert a key-value pair at index
- {
- byte[] oldBytes = fBytes;
- int valLen = (value != null) ? value.length : 0;
- int insertion = 0;
- int newLen, avLen;
-
- // locate the insertion point
- for ( int i=0; i < index && insertion < fBytes.length; i++)
- insertion += (0xFF & (fBytes[ insertion] + 1));
-
- avLen = keyBytes.length + valLen + (value != null ? 1 : 0);
- newLen = avLen + oldBytes.length + 1;
-
- fBytes = new byte[ newLen];
- System.arraycopy( oldBytes, 0, fBytes, 0, insertion);
- int secondHalfLen = oldBytes.length - insertion;
- System.arraycopy( oldBytes, insertion, fBytes, newLen - secondHalfLen, secondHalfLen);
- fBytes[ insertion] = ( byte) avLen;
- System.arraycopy( keyBytes, 0, fBytes, insertion + 1, keyBytes.length);
- if ( value != null)
- {
- fBytes[ insertion + 1 + keyBytes.length] = kAttrSep;
- System.arraycopy( value, 0, fBytes, insertion + keyBytes.length + 2, valLen);
- }
- }
-
- /** Remove a key/value pair from the TXT record. Returns index it was at, or -1 if not found. */
- public int remove( String key)
- {
- int avStart = 0;
-
- for ( int i=0; avStart < fBytes.length; i++)
- {
- int avLen = fBytes[ avStart];
- if ( key.length() <= avLen &&
- ( key.length() == avLen || fBytes[ avStart + key.length() + 1] == kAttrSep))
- {
- String s = new String( fBytes, avStart + 1, key.length());
- if ( 0 == key.compareToIgnoreCase( s))
- {
- byte[] oldBytes = fBytes;
- fBytes = new byte[ oldBytes.length - avLen - 1];
- System.arraycopy( oldBytes, 0, fBytes, 0, avStart);
- System.arraycopy( oldBytes, avStart + avLen + 1, fBytes, avStart, oldBytes.length - avStart - avLen - 1);
- return i;
- }
- }
- avStart += (0xFF & (avLen + 1));
- }
- return -1;
- }
-
- /** Return the number of keys in the TXT record. */
- public int size()
- {
- int i, avStart;
-
- for ( i=0, avStart=0; avStart < fBytes.length; i++)
- avStart += (0xFF & (fBytes[ avStart] + 1));
- return i;
- }
-
- /** Return true if key is present in the TXT record, false if not. */
- public boolean contains( String key)
- {
- String s = null;
-
- for ( int i=0; null != ( s = this.getKey( i)); i++)
- if ( 0 == key.compareToIgnoreCase( s))
- return true;
- return false;
- }
-
- /** Return a key in the TXT record by zero-based index. Returns null if index exceeds the total number of keys. */
- public String getKey( int index)
- {
- int avStart = 0;
-
- for ( int i=0; i < index && avStart < fBytes.length; i++)
- avStart += fBytes[ avStart] + 1;
-
- if ( avStart < fBytes.length)
- {
- int avLen = fBytes[ avStart];
- int aLen = 0;
-
- for ( aLen=0; aLen < avLen; aLen++)
- if ( fBytes[ avStart + aLen + 1] == kAttrSep)
- break;
- return new String( fBytes, avStart + 1, aLen);
- }
- return null;
- }
-
- /**
- Look up a key in the TXT record by zero-based index and return its value. <P>
- Returns null if index exceeds the total number of keys.
- Returns null if the key is present with no value.
- */
- public byte[] getValue( int index)
- {
- int avStart = 0;
- byte[] value = null;
-
- for ( int i=0; i < index && avStart < fBytes.length; i++)
- avStart += fBytes[ avStart] + 1;
-
- if ( avStart < fBytes.length)
- {
- int avLen = fBytes[ avStart];
- int aLen = 0;
-
- for ( aLen=0; aLen < avLen; aLen++)
- {
- if ( fBytes[ avStart + aLen + 1] == kAttrSep)
- {
- value = new byte[ avLen - aLen - 1];
- System.arraycopy( fBytes, avStart + aLen + 2, value, 0, avLen - aLen - 1);
- break;
- }
- }
- }
- return value;
- }
-
- /** Converts the result of getValue() to a string in the platform default character set. */
- public String getValueAsString( int index)
- {
- byte[] value = this.getValue( index);
- return value != null ? new String( value) : null;
- }
-
- /** Get the value associated with a key. Will be null if the key is not defined.
- Array will have length 0 if the key is defined with an = but no value.<P>
-
- @param forKey
- The left-hand side of the key-value pair.
- <P>
- @return The binary representation of the value.
- */
- public byte[] getValue( String forKey)
- {
- String s = null;
- int i;
-
- for ( i=0; null != ( s = this.getKey( i)); i++)
- if ( 0 == forKey.compareToIgnoreCase( s))
- return this.getValue( i);
- return null;
- }
-
- /** Converts the result of getValue() to a string in the platform default character set.<P>
-
- @param forKey
- The left-hand side of the key-value pair.
- <P>
- @return The value represented in the default platform character set.
- */
- public String getValueAsString( String forKey)
- {
- byte[] val = this.getValue( forKey);
- return val != null ? new String( val) : null;
- }
-
- /** Return the contents of the TXT record as raw bytes. */
- public byte[] getRawBytes() { return (byte[]) fBytes.clone(); }
-
- /** Return a string representation of the object. */
- public String toString()
- {
- String a, result = null;
-
- for ( int i=0; null != ( a = this.getKey( i)); i++)
- {
- String av = String.valueOf( i) + "={" + a;
- String val = this.getValueAsString( i);
- if ( val != null)
- av += "=" + val + "}";
- else
- av += "}";
- if ( result == null)
- result = av;
- else
- result = result + ", " + av;
- }
- return result != null ? result : "";
- }
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * This class handles TXT record data for DNS based service discovery as specified at
+ * http://tools.ietf.org/html/draft-cheshire-dnsext-dns-sd-11
+ *
+ * DNS-SD specifies that a TXT record corresponding to an SRV record consist of
+ * a packed array of bytes, each preceded by a length byte. Each string
+ * is an attribute-value pair.
+ *
+ * The DnsSdTxtRecord object stores the entire TXT data as a single byte array, traversing it
+ * as need be to implement its various methods.
+ *
+ * @hide
+ */
+public class DnsSdTxtRecord implements Parcelable {
+ private static final byte mSeperator = '=';
+
+ private byte[] mData;
+
+ /** Constructs a new, empty TXT record. */
+ public DnsSdTxtRecord() {
+ mData = new byte[0];
+ }
+
+ /** Constructs a new TXT record from a byte array in the standard format. */
+ public DnsSdTxtRecord(byte[] data) {
+ mData = (byte[]) data.clone();
+ }
+
+ /** Copy constructor */
+ public DnsSdTxtRecord(DnsSdTxtRecord src) {
+ if (src != null && src.mData != null) {
+ mData = (byte[]) src.mData.clone();
+ }
+ }
+
+ /**
+ * Set a key/value pair. Setting an existing key will replace its value.
+ * @param key Must be ascii with no '='
+ * @param value matching value to key
+ */
+ public void set(String key, String value) {
+ byte[] keyBytes;
+ byte[] valBytes;
+ int valLen;
+
+ if (value != null) {
+ valBytes = value.getBytes();
+ valLen = valBytes.length;
+ } else {
+ valBytes = null;
+ valLen = 0;
+ }
+
+ try {
+ keyBytes = key.getBytes("US-ASCII");
+ }
+ catch (java.io.UnsupportedEncodingException e) {
+ throw new IllegalArgumentException("key should be US-ASCII");
+ }
+
+ for (int i = 0; i < keyBytes.length; i++) {
+ if (keyBytes[i] == '=') {
+ throw new IllegalArgumentException("= is not a valid character in key");
+ }
+ }
+
+ if (keyBytes.length + valLen >= 255) {
+ throw new IllegalArgumentException("Key and Value length cannot exceed 255 bytes");
+ }
+
+ int currentLoc = remove(key);
+ if (currentLoc == -1)
+ currentLoc = keyCount();
+
+ insert(keyBytes, valBytes, currentLoc);
+ }
+
+ /**
+ * Get a value for a key
+ *
+ * @param key
+ * @return The value associated with the key
+ */
+ public String get(String key) {
+ byte[] val = this.getValue(key);
+ return val != null ? new String(val) : null;
+ }
+
+ /** Remove a key/value pair. If found, returns the index or -1 if not found */
+ public int remove(String key) {
+ int avStart = 0;
+
+ for (int i=0; avStart < mData.length; i++) {
+ int avLen = mData[avStart];
+ if (key.length() <= avLen &&
+ (key.length() == avLen || mData[avStart + key.length() + 1] == mSeperator)) {
+ String s = new String(mData, avStart + 1, key.length());
+ if (0 == key.compareToIgnoreCase(s)) {
+ byte[] oldBytes = mData;
+ mData = new byte[oldBytes.length - avLen - 1];
+ System.arraycopy(oldBytes, 0, mData, 0, avStart);
+ System.arraycopy(oldBytes, avStart + avLen + 1, mData, avStart,
+ oldBytes.length - avStart - avLen - 1);
+ return i;
+ }
+ }
+ avStart += (0xFF & (avLen + 1));
+ }
+ return -1;
+ }
+
+ /** Return the count of keys */
+ public int keyCount() {
+ int count = 0, nextKey;
+ for (nextKey = 0; nextKey < mData.length; count++) {
+ nextKey += (0xFF & (mData[nextKey] + 1));
+ }
+ return count;
+ }
+
+ /** Return true if key is present, false if not. */
+ public boolean contains(String key) {
+ String s = null;
+ for (int i = 0; null != (s = this.getKey(i)); i++) {
+ if (0 == key.compareToIgnoreCase(s)) return true;
+ }
+ return false;
+ }
+
+ /* Gets the size in bytes */
+ public int size() {
+ return mData.length;
+ }
+
+ /* Gets the raw data in bytes */
+ public byte[] getRawData() {
+ return mData;
+ }
+
+ private void insert(byte[] keyBytes, byte[] value, int index) {
+ byte[] oldBytes = mData;
+ int valLen = (value != null) ? value.length : 0;
+ int insertion = 0;
+ int newLen, avLen;
+
+ for (int i = 0; i < index && insertion < mData.length; i++) {
+ insertion += (0xFF & (mData[insertion] + 1));
+ }
+
+ avLen = keyBytes.length + valLen + (value != null ? 1 : 0);
+ newLen = avLen + oldBytes.length + 1;
+
+ mData = new byte[newLen];
+ System.arraycopy(oldBytes, 0, mData, 0, insertion);
+ int secondHalfLen = oldBytes.length - insertion;
+ System.arraycopy(oldBytes, insertion, mData, newLen - secondHalfLen, secondHalfLen);
+ mData[insertion] = (byte) avLen;
+ System.arraycopy(keyBytes, 0, mData, insertion + 1, keyBytes.length);
+ if (value != null) {
+ mData[insertion + 1 + keyBytes.length] = mSeperator;
+ System.arraycopy(value, 0, mData, insertion + keyBytes.length + 2, valLen);
+ }
+ }
+
+ /** Return a key in the TXT record by zero-based index. Returns null if index exceeds the total number of keys. */
+ private String getKey(int index) {
+ int avStart = 0;
+
+ for (int i=0; i < index && avStart < mData.length; i++) {
+ avStart += mData[avStart] + 1;
+ }
+
+ if (avStart < mData.length) {
+ int avLen = mData[avStart];
+ int aLen = 0;
+
+ for (aLen=0; aLen < avLen; aLen++) {
+ if (mData[avStart + aLen + 1] == mSeperator) break;
+ }
+ return new String(mData, avStart + 1, aLen);
+ }
+ return null;
+ }
+
+ /**
+ * Look up a key in the TXT record by zero-based index and return its value.
+ * Returns null if index exceeds the total number of keys.
+ * Returns null if the key is present with no value.
+ */
+ private byte[] getValue(int index) {
+ int avStart = 0;
+ byte[] value = null;
+
+ for (int i=0; i < index && avStart < mData.length; i++) {
+ avStart += mData[avStart] + 1;
+ }
+
+ if (avStart < mData.length) {
+ int avLen = mData[avStart];
+ int aLen = 0;
+
+ for (aLen=0; aLen < avLen; aLen++) {
+ if (mData[avStart + aLen + 1] == mSeperator) {
+ value = new byte[avLen - aLen - 1];
+ System.arraycopy(mData, avStart + aLen + 2, value, 0, avLen - aLen - 1);
+ break;
+ }
+ }
+ }
+ return value;
+ }
+
+ private String getValueAsString(int index) {
+ byte[] value = this.getValue(index);
+ return value != null ? new String(value) : null;
+ }
+
+ private byte[] getValue(String forKey) {
+ String s = null;
+ int i;
+
+ for (i = 0; null != (s = this.getKey(i)); i++) {
+ if (0 == forKey.compareToIgnoreCase(s)) {
+ return this.getValue(i);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Return a string representation.
+ * Example : {key1=value1},{key2=value2}..
+ *
+ * For a key say like "key3" with null value
+ * {key1=value1},{key2=value2}{key3}
+ */
+ public String toString() {
+ String a, result = null;
+
+ for (int i = 0; null != (a = this.getKey(i)); i++) {
+ String av = "{" + a;
+ String val = this.getValueAsString(i);
+ if (val != null)
+ av += "=" + val + "}";
+ else
+ av += "}";
+ if (result == null)
+ result = av;
+ else
+ result = result + ", " + av;
+ }
+ return result != null ? result : "";
+ }
+
+ /** Implement the Parcelable interface */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByteArray(mData);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Creator<DnsSdTxtRecord> CREATOR =
+ new Creator<DnsSdTxtRecord>() {
+ public DnsSdTxtRecord createFromParcel(Parcel in) {
+ DnsSdTxtRecord info = new DnsSdTxtRecord();
+ in.readByteArray(info.mData);
+ return info;
+ }
+
+ public DnsSdTxtRecord[] newArray(int size) {
+ return new DnsSdTxtRecord[size];
+ }
+ };
}
diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl
new file mode 100644
index 0000000..077a675
--- /dev/null
+++ b/core/java/android/net/nsd/INsdManager.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.nsd;
+
+import android.os.Messenger;
+
+/**
+ * Interface that NsdService implements
+ *
+ * {@hide}
+ */
+interface INsdManager
+{
+ Messenger getMessenger();
+}
diff --git a/core/java/android/net/nsd/NetworkServiceInfo.java b/core/java/android/net/nsd/NetworkServiceInfo.java
new file mode 100644
index 0000000..34d83d1
--- /dev/null
+++ b/core/java/android/net/nsd/NetworkServiceInfo.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.nsd;
+
+/**
+ * Interface for a network service.
+ *
+ * {@hide}
+ */
+public interface NetworkServiceInfo {
+
+ String getServiceName();
+ void setServiceName(String s);
+
+ String getServiceType();
+ void setServiceType(String s);
+
+}
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
new file mode 100644
index 0000000..a109a98
--- /dev/null
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.nsd;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.Messenger;
+import android.util.Log;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+/**
+ * The Network Service Discovery Manager class provides the API for service
+ * discovery. Service discovery enables applications to discover and connect with services
+ * on a network. Example applications include a game application discovering another instance
+ * of the game application or a printer application discovering other printers on a network.
+ *
+ * <p> The API is asynchronous and responses to requests from an application are on listener
+ * callbacks provided by the application. The application needs to do an initialization with
+ * {@link #initialize} before doing any operation.
+ *
+ * <p> Android currently supports DNS based service discovery and it is limited to a local
+ * network with the use of multicast DNS. In future, this class will be
+ * extended to support other service discovery mechanisms.
+ *
+ * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
+ * Context.getSystemService(Context.NSD_SERVICE)}.
+ * @hide
+ *
+ */
+public class NsdManager {
+ private static final String TAG = "NsdManager";
+ INsdManager mService;
+
+ private static final int BASE = Protocol.BASE_NSD_MANAGER;
+
+ /** @hide */
+ public static final int DISCOVER_SERVICES = BASE + 1;
+ /** @hide */
+ public static final int DISCOVER_SERVICES_STARTED = BASE + 2;
+ /** @hide */
+ public static final int DISCOVER_SERVICES_FAILED = BASE + 3;
+ /** @hide */
+ public static final int SERVICE_FOUND = BASE + 4;
+ /** @hide */
+ public static final int SERVICE_LOST = BASE + 5;
+
+ /** @hide */
+ public static final int STOP_DISCOVERY = BASE + 6;
+ /** @hide */
+ public static final int STOP_DISCOVERY_FAILED = BASE + 7;
+ /** @hide */
+ public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 8;
+
+ /** @hide */
+ public static final int REGISTER_SERVICE = BASE + 9;
+ /** @hide */
+ public static final int REGISTER_SERVICE_FAILED = BASE + 10;
+ /** @hide */
+ public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11;
+
+ /** @hide */
+ public static final int UPDATE_SERVICE = BASE + 12;
+ /** @hide */
+ public static final int UPDATE_SERVICE_FAILED = BASE + 13;
+ /** @hide */
+ public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 14;
+
+ /** @hide */
+ public static final int RESOLVE_SERVICE = BASE + 15;
+ /** @hide */
+ public static final int RESOLVE_SERVICE_FAILED = BASE + 16;
+ /** @hide */
+ public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 17;
+
+ /**
+ * 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.
+ */
+ public NsdManager(INsdManager service) {
+ mService = service;
+ }
+
+ /**
+ * Indicates that the operation failed due to an internal error.
+ */
+ public static final int ERROR = 0;
+
+ /**
+ * Indicates that the operation failed because service discovery is unsupported on the device.
+ */
+ public static final int UNSUPPORTED = 1;
+
+ /**
+ * Indicates that the operation failed because the framework is busy and
+ * unable to service the request
+ */
+ public static final int BUSY = 2;
+
+ /** Interface for callback invocation when framework channel is connected or lost */
+ public interface ChannelListener {
+ public void onChannelConnected(Channel c);
+ /**
+ * The channel to the framework has been disconnected.
+ * Application could try re-initializing using {@link #initialize}
+ */
+ public void onChannelDisconnected();
+ }
+
+ public interface ActionListener {
+
+ public void onFailure(int errorCode);
+
+ public void onSuccess();
+ }
+
+ public interface DnsSdDiscoveryListener {
+
+ public void onFailure(int errorCode);
+
+ public void onStarted(String registrationType);
+
+ public void onServiceFound(DnsSdServiceInfo serviceInfo);
+
+ public void onServiceLost(DnsSdServiceInfo serviceInfo);
+
+ }
+
+ public interface DnsSdRegisterListener {
+
+ public void onFailure(int errorCode);
+
+ public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo);
+ }
+
+ public interface DnsSdUpdateRegistrationListener {
+
+ public void onFailure(int errorCode);
+
+ public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord);
+ }
+
+ public interface DnsSdResolveListener {
+
+ public void onFailure(int errorCode);
+
+ public void onServiceResolved(DnsSdServiceInfo serviceInfo);
+ }
+
+ /**
+ * A channel that connects the application to the NetworkService framework.
+ * Most service operations require a Channel as an argument. An instance of Channel is obtained
+ * by doing a call on {@link #initialize}
+ */
+ public static class Channel {
+ Channel(Looper looper, ChannelListener l) {
+ mAsyncChannel = new AsyncChannel();
+ mHandler = new ServiceHandler(looper);
+ mChannelListener = l;
+ }
+ private ChannelListener mChannelListener;
+ private DnsSdDiscoveryListener mDnsSdDiscoveryListener;
+ private ActionListener mDnsSdStopDiscoveryListener;
+ private DnsSdRegisterListener mDnsSdRegisterListener;
+ private DnsSdUpdateRegistrationListener mDnsSdUpdateListener;
+ private DnsSdResolveListener mDnsSdResolveListener;
+
+ AsyncChannel mAsyncChannel;
+ ServiceHandler mHandler;
+ class ServiceHandler extends Handler {
+ ServiceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ break;
+ case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
+ if (mChannelListener != null) {
+ mChannelListener.onChannelConnected(Channel.this);
+ }
+ break;
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ if (mChannelListener != null) {
+ mChannelListener.onChannelDisconnected();
+ mChannelListener = null;
+ }
+ break;
+ case DISCOVER_SERVICES_STARTED:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onStarted((String) message.obj);
+ }
+ break;
+ case DISCOVER_SERVICES_FAILED:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onFailure(message.arg1);
+ }
+ break;
+ case SERVICE_FOUND:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onServiceFound(
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ case SERVICE_LOST:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onServiceLost(
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ case STOP_DISCOVERY_FAILED:
+ if (mDnsSdStopDiscoveryListener != null) {
+ mDnsSdStopDiscoveryListener.onFailure(message.arg1);
+ }
+ break;
+ case STOP_DISCOVERY_SUCCEEDED:
+ if (mDnsSdStopDiscoveryListener != null) {
+ mDnsSdStopDiscoveryListener.onSuccess();
+ }
+ break;
+ case REGISTER_SERVICE_FAILED:
+ if (mDnsSdRegisterListener != null) {
+ mDnsSdRegisterListener.onFailure(message.arg1);
+ }
+ break;
+ case REGISTER_SERVICE_SUCCEEDED:
+ if (mDnsSdRegisterListener != null) {
+ mDnsSdRegisterListener.onServiceRegistered(message.arg1,
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ case UPDATE_SERVICE_FAILED:
+ if (mDnsSdUpdateListener != null) {
+ mDnsSdUpdateListener.onFailure(message.arg1);
+ }
+ break;
+ case UPDATE_SERVICE_SUCCEEDED:
+ if (mDnsSdUpdateListener != null) {
+ mDnsSdUpdateListener.onServiceUpdated(message.arg1,
+ (DnsSdTxtRecord) message.obj);
+ }
+ break;
+ case RESOLVE_SERVICE_FAILED:
+ if (mDnsSdResolveListener != null) {
+ mDnsSdResolveListener.onFailure(message.arg1);
+ }
+ break;
+ case RESOLVE_SERVICE_SUCCEEDED:
+ if (mDnsSdResolveListener != null) {
+ mDnsSdResolveListener.onServiceResolved(
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ default:
+ Log.d(TAG, "Ignored " + message);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers the application with the service discovery framework. This function
+ * must be the first to be called before any other operations are performed. No service
+ * discovery operations must be performed until the ChannelListener callback notifies
+ * that the channel is connected
+ *
+ * @param srcContext is the context of the source
+ * @param srcLooper is the Looper on which the callbacks are receivied
+ * @param listener for callback at loss of framework communication.
+ */
+ public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
+ Messenger messenger = getMessenger();
+ if (messenger == null) throw new RuntimeException("Failed to initialize");
+ if (listener == null) throw new IllegalArgumentException("ChannelListener cannot be null");
+
+ Channel c = new Channel(srcLooper, listener);
+ c.mAsyncChannel.connect(srcContext, c.mHandler, messenger);
+ }
+
+ /**
+ * Set the listener for service discovery. Can be null.
+ */
+ public void setDiscoveryListener(Channel c, DnsSdDiscoveryListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdDiscoveryListener = b;
+ }
+
+ /**
+ * Set the listener for stop service discovery. Can be null.
+ */
+ public void setStopDiscoveryListener(Channel c, ActionListener a) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdStopDiscoveryListener = a;
+ }
+
+ /**
+ * Set the listener for service registration. Can be null.
+ */
+ public void setRegisterListener(Channel c, DnsSdRegisterListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdRegisterListener = b;
+ }
+
+ /**
+ * Set the listener for service registration. Can be null.
+ */
+ public void setUpdateRegistrationListener(Channel c, DnsSdUpdateRegistrationListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdUpdateListener = b;
+ }
+
+ /**
+ * Set the listener for service resolution. Can be null.
+ */
+ public void setResolveListener(Channel c, DnsSdResolveListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdResolveListener = b;
+ }
+
+ public void registerService(Channel c, DnsSdServiceInfo serviceInfo) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
+ c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo);
+ }
+
+ public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord);
+ }
+
+ public void discoverServices(Channel c, String serviceType) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ if (c.mDnsSdDiscoveryListener == null) throw new
+ IllegalStateException("Discovery listener needs to be set first");
+ DnsSdServiceInfo s = new DnsSdServiceInfo();
+ s.setServiceType(serviceType);
+ c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s);
+ }
+
+ public void stopServiceDiscovery(Channel c) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mAsyncChannel.sendMessage(STOP_DISCOVERY);
+ }
+
+ public void resolveService(Channel c, DnsSdServiceInfo serviceInfo) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
+ if (c.mDnsSdResolveListener == null) throw new
+ IllegalStateException("Resolve listener needs to be set first");
+ c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo);
+ }
+
+ /**
+ * Get a reference to NetworkService handler. This is used to establish
+ * an AsyncChannel communication with the service
+ *
+ * @return Messenger pointing to the NetworkService handler
+ */
+ private Messenger getMessenger() {
+ try {
+ return mService.getMessenger();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index d462d7f..7c2b1b5 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -49,7 +49,7 @@ public class Protocol {
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
public static final int BASE_DATA_CONNECTION_TRACKER = 0x00042000;
-
public static final int BASE_DNS_PINGER = 0x00050000;
+ public static final int BASE_NSD_MANAGER = 0x00060000;
//TODO: define all used protocols
}
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
new file mode 100644
index 0000000..768be7d
--- /dev/null
+++ b/services/java/com/android/server/NsdService.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.nsd.DnsSdServiceInfo;
+import android.net.nsd.DnsSdTxtRecord;
+import android.net.nsd.INsdManager;
+import android.net.nsd.NsdManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.IBinder;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.List;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.AsyncChannel;
+import com.android.server.am.BatteryStatsService;
+import com.android.server.NativeDaemonConnector.Command;
+import com.android.internal.R;
+
+/**
+ * Network Service Discovery Service handles remote service discovery operation requests by
+ * implementing the INsdManager interface.
+ *
+ * @hide
+ */
+public class NsdService extends INsdManager.Stub {
+ private static final String TAG = "NsdService";
+ private static final String MDNS_TAG = "mDnsConnector";
+
+ private static final boolean DBG = true;
+
+ private Context mContext;
+
+ /**
+ * Clients receiving asynchronous messages
+ */
+ private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>();
+
+ private AsyncChannel mReplyChannel = new AsyncChannel();
+
+ /**
+ * Handles client(app) connections
+ */
+ private class AsyncServiceHandler extends Handler {
+
+ AsyncServiceHandler(android.os.Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ AsyncChannel c = (AsyncChannel) msg.obj;
+ if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
+ c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
+ mClients.add(c);
+ } else {
+ Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
+ }
+ break;
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
+ Slog.e(TAG, "Send failed, client connection lost");
+ } else {
+ if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
+ }
+ mClients.remove((AsyncChannel) msg.obj);
+ break;
+ case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
+ AsyncChannel ac = new AsyncChannel();
+ ac.connect(mContext, this, msg.replyTo);
+ break;
+ case NsdManager.DISCOVER_SERVICES:
+ if (DBG) Slog.d(TAG, "Discover services");
+ DnsSdServiceInfo s = (DnsSdServiceInfo) msg.obj;
+ discoverServices(1, s.getServiceType());
+ mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED);
+ break;
+ case NsdManager.STOP_DISCOVERY:
+ if (DBG) Slog.d(TAG, "Stop service discovery");
+ mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED);
+ break;
+ case NsdManager.REGISTER_SERVICE:
+ if (DBG) Slog.d(TAG, "Register service");
+ mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED);
+ break;
+ case NsdManager.UPDATE_SERVICE:
+ if (DBG) Slog.d(TAG, "Update service");
+ mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED);
+ break;
+ default:
+ Slog.d(TAG, "NsdServicehandler.handleMessage ignoring msg=" + msg);
+ break;
+ }
+ }
+ }
+ private AsyncServiceHandler mAsyncServiceHandler;
+
+ private NativeDaemonConnector mNativeConnector;
+ private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
+
+ private NsdService(Context context) {
+ mContext = context;
+
+ HandlerThread nsdThread = new HandlerThread("NsdService");
+ nsdThread.start();
+ mAsyncServiceHandler = new AsyncServiceHandler(nsdThread.getLooper());
+
+ /*
+ mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
+ MDNS_TAG, 25);
+ Thread th = new Thread(mNativeConnector, MDNS_TAG);
+ th.start();
+ */
+ }
+
+ public static NsdService create(Context context) throws InterruptedException {
+ NsdService service = new NsdService(context);
+ /* service.mNativeDaemonConnected.await(); */
+ return service;
+ }
+
+ public Messenger getMessenger() {
+ return new Messenger(mAsyncServiceHandler);
+ }
+
+ /* These should be in sync with system/netd/mDnsResponseCode.h */
+ class NativeResponseCode {
+ public static final int SERVICE_FOUND = 101;
+ public static final int SERVICE_LOST = 102;
+ public static final int SERVICE_DISCOVERY_FAILED = 103;
+
+ public static final int SERVICE_REGISTERED = 104;
+ public static final int SERVICE_REGISTRATION_FAILED = 105;
+
+ public static final int SERVICE_UPDATED = 106;
+ public static final int SERVICE_UPDATE_FAILED = 107;
+
+ public static final int SERVICE_RESOLVED = 108;
+ public static final int SERVICE_RESOLUTION_FAILED = 109;
+ }
+
+
+ class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
+ public void onDaemonConnected() {
+ mNativeDaemonConnected.countDown();
+ }
+
+ public boolean onEvent(int code, String raw, String[] cooked) {
+ switch (code) {
+ case NativeResponseCode.SERVICE_FOUND:
+ /* NNN uniqueId serviceName regType */
+ break;
+ case NativeResponseCode.SERVICE_LOST:
+ /* NNN uniqueId serviceName regType */
+ break;
+ case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
+ /* NNN uniqueId errorCode */
+ break;
+ case NativeResponseCode.SERVICE_REGISTERED:
+ /* NNN regId serviceName regType */
+ break;
+ case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
+ /* NNN regId errorCode */
+ break;
+ case NativeResponseCode.SERVICE_UPDATED:
+ /* NNN regId */
+ break;
+ case NativeResponseCode.SERVICE_UPDATE_FAILED:
+ /* NNN regId errorCode */
+ break;
+ case NativeResponseCode.SERVICE_RESOLVED:
+ /* NNN resolveId fullName hostName port txtlen txtdata */
+ break;
+ case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
+ /* NNN resovleId errorCode */
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+ }
+
+ private void registerService(int regId, DnsSdServiceInfo service) {
+ try {
+ //Add txtlen and txtdata
+ mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(),
+ service.getServiceType(), service.getPort());
+ } catch(NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to execute registerService");
+ }
+ }
+
+ private void updateService(int regId, DnsSdTxtRecord t) {
+ try {
+ if (t == null) return;
+ mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
+ } catch(NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to updateServices");
+ }
+ }
+
+ private void discoverServices(int discoveryId, String serviceType) {
+ try {
+ mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
+ } catch(NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to discoverServices");
+ }
+ }
+
+ private void stopServiceDiscovery(int discoveryId) {
+ try {
+ mNativeConnector.execute("mdnssd", "stopdiscover", discoveryId);
+ } catch(NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to stopServiceDiscovery");
+ }
+ }
+
+ private void resolveService(DnsSdServiceInfo service) {
+ try {
+ mNativeConnector.execute("mdnssd", "resolve", service.getServiceName(),
+ service.getServiceType());
+ } catch(NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to resolveService");
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ pw.println("Internal state:");
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 423dad6..e091edf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -120,6 +120,7 @@ class ServerThread extends Thread {
ConnectivityService connectivity = null;
WifiP2pService wifiP2p = null;
WifiService wifi = null;
+ NsdService serviceDiscovery= null;
IPackageManager pm = null;
Context context = null;
WindowManagerService wm = null;
@@ -394,6 +395,15 @@ class ServerThread extends Thread {
}
try {
+ Slog.i(TAG, "Network Service Discovery Service");
+ serviceDiscovery = NsdService.create(context);
+ ServiceManager.addService(
+ Context.NSD_SERVICE, serviceDiscovery);
+ } catch (Throwable e) {
+ reportWtf("starting Service Discovery Service", e);
+ }
+
+ try {
Slog.i(TAG, "Throttle Service");
throttle = new ThrottleService(context);
ServiceManager.addService(