Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ef889bf authored by Irfan Sheriff's avatar Irfan Sheriff
Browse files

Add user control to turn on/off nsd

Change-Id: Ide3cc20adb21ac6dffaf6b9b9136d77a129afa3b
parent c5cbcb51
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -26,4 +26,5 @@ import android.os.Messenger;
interface INsdManager
interface INsdManager
{
{
    Messenger getMessenger();
    Messenger getMessenger();
    void setEnabled(boolean enable);
}
}
+55 −2
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package android.net.nsd;
package android.net.nsd;


import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.content.Context;
import android.os.Binder;
import android.os.Binder;
import android.os.IBinder;
import android.os.IBinder;
@@ -133,6 +135,44 @@ public class NsdManager {
    private static final String TAG = "NsdManager";
    private static final String TAG = "NsdManager";
    INsdManager mService;
    INsdManager mService;


    /**
     * 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.
     *
     * @see #EXTRA_NSD_STATE
     * @hide
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String NSD_STATE_CHANGED_ACTION =
        "android.net.nsd.STATE_CHANGED";

    /**
     * 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)}.
     *
     * @see #NSD_STATE_DISABLED
     * @see #NSD_STATE_ENABLED
     * @hide
     */
    public static final String EXTRA_NSD_STATE = "nsd_state";

    /**
     * Network service discovery is disabled
     *
     * @see #NSD_STATE_CHANGED_ACTION
     * @hide
     */
    public static final int NSD_STATE_DISABLED = 1;

    /**
     * Network service discovery is enabled
     *
     * @see #NSD_STATE_CHANGED_ACTION
     * @hide
     */
    public static final int NSD_STATE_ENABLED = 2;

    private static final int BASE = Protocol.BASE_NSD_MANAGER;
    private static final int BASE = Protocol.BASE_NSD_MANAGER;


    /** @hide */
    /** @hide */
@@ -188,6 +228,12 @@ public class NsdManager {
    /** @hide */
    /** @hide */
    public static final int STOP_RESOLVE_SUCCEEDED                  = BASE + 23;
    public static final int STOP_RESOLVE_SUCCEEDED                  = BASE + 23;


    /** @hide */
    public static final int ENABLE                                  = BASE + 24;
    /** @hide */
    public static final int DISABLE                                 = BASE + 25;


    /**
    /**
     * Create a new Nsd instance. Applications use
     * Create a new Nsd instance. Applications use
     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -312,8 +358,8 @@ public class NsdManager {
        private DnsSdResolveListener mDnsSdResolveListener;
        private DnsSdResolveListener mDnsSdResolveListener;
        private ActionListener mDnsSdStopResolveListener;
        private ActionListener mDnsSdStopResolveListener;


        AsyncChannel mAsyncChannel;
        private AsyncChannel mAsyncChannel;
        ServiceHandler mHandler;
        private ServiceHandler mHandler;
        class ServiceHandler extends Handler {
        class ServiceHandler extends Handler {
            ServiceHandler(Looper looper) {
            ServiceHandler(Looper looper) {
                super(looper);
                super(looper);
@@ -594,6 +640,13 @@ public class NsdManager {
        c.mAsyncChannel.sendMessage(STOP_RESOLVE);
        c.mAsyncChannel.sendMessage(STOP_RESOLVE);
    }
    }


    /** Internal use only @hide */
    public void setEnabled(boolean enabled) {
        try {
            mService.setEnabled(enabled);
        } catch (RemoteException e) { }
    }

    /**
    /**
     * Get a reference to NetworkService handler. This is used to establish
     * Get a reference to NetworkService handler. This is used to establish
     * an AsyncChannel communication with the service
     * an AsyncChannel communication with the service
+6 −0
Original line number Original line Diff line number Diff line
@@ -3276,6 +3276,12 @@ public final class Settings {
        public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
        public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
            "wifi_mobile_data_transition_wakelock_timeout_ms";
            "wifi_mobile_data_transition_wakelock_timeout_ms";


        /**
         * Whether network service discovery is enabled.
         * @hide
         */
        public static final String NSD_ON = "nsd_on";

        /**
        /**
         * Whether background data usage is allowed by the user. See
         * Whether background data usage is allowed by the user. See
         * ConnectivityManager for more info.
         * ConnectivityManager for more info.
+324 −144
Original line number Original line Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server;
package com.android.server;


import android.content.Context;
import android.content.Context;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.net.nsd.DnsSdServiceInfo;
import android.net.nsd.DnsSdServiceInfo;
import android.net.nsd.DnsSdTxtRecord;
import android.net.nsd.DnsSdTxtRecord;
@@ -28,6 +30,7 @@ import android.os.HandlerThread;
import android.os.Message;
import android.os.Message;
import android.os.Messenger;
import android.os.Messenger;
import android.os.IBinder;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Slog;
import android.util.Slog;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
@@ -41,6 +44,9 @@ import java.util.concurrent.CountDownLatch;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.am.BatteryStatsService;
import com.android.server.am.BatteryStatsService;
import com.android.server.NativeDaemonConnector.Command;
import com.android.server.NativeDaemonConnector.Command;
import com.android.internal.R;
import com.android.internal.R;
@@ -58,6 +64,8 @@ public class NsdService extends INsdManager.Stub {
    private static final boolean DBG = true;
    private static final boolean DBG = true;


    private Context mContext;
    private Context mContext;
    private ContentResolver mContentResolver;
    private NsdStateMachine mNsdStateMachine;


    /**
    /**
     * Clients receiving asynchronous messages
     * Clients receiving asynchronous messages
@@ -69,19 +77,55 @@ public class NsdService extends INsdManager.Stub {
    private int INVALID_ID = 0;
    private int INVALID_ID = 0;
    private int mUniqueId = 1;
    private int mUniqueId = 1;


    /**
    private static final int BASE = Protocol.BASE_NSD_MANAGER;
     * Handles client(app) connections
    private static final int CMD_TO_STRING_COUNT = NsdManager.STOP_RESOLVE - BASE + 1;
     */
    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
    private class AsyncServiceHandler extends Handler {

    static {
        sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
        sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
        sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
        sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
        sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
        sCmdToString[NsdManager.STOP_RESOLVE - BASE] = "STOP-RESOLVE";
    }


        AsyncServiceHandler(android.os.Looper looper) {
    private static String cmdToString(int cmd) {
            super(looper);
        cmd -= BASE;
        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
            return sCmdToString[cmd];
        } else {
            return null;
        }
    }
    }


    private class NsdStateMachine extends StateMachine {

        private DefaultState mDefaultState = new DefaultState();
        private DisabledState mDisabledState = new DisabledState();
        private EnabledState mEnabledState = new EnabledState();

        @Override
        @Override
        public void handleMessage(Message msg) {
        protected String getMessageInfo(Message msg) {
            ClientInfo clientInfo;
            return cmdToString(msg.what);
            DnsSdServiceInfo servInfo;
        }

        NsdStateMachine(String name) {
            super(name);
            addState(mDefaultState);
                addState(mDisabledState, mDefaultState);
                addState(mEnabledState, mDefaultState);
            if (isNsdEnabled()) {
                setInitialState(mEnabledState);
            } else {
                setInitialState(mDisabledState);
            }
            setProcessedMessagesSize(25);
        }

        class DefaultState extends State {
            @Override
            public boolean processMessage(Message msg) {
                switch (msg.what) {
                switch (msg.what) {
                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
@@ -89,9 +133,6 @@ public class NsdService extends INsdManager.Stub {
                            if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
                            if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
                            c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
                            c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
                            ClientInfo cInfo = new ClientInfo(c, msg.replyTo);
                            ClientInfo cInfo = new ClientInfo(c, msg.replyTo);
                        if (mClients.size() == 0) {
                            startMDnsDaemon();
                        }
                            mClients.put(msg.replyTo, cInfo);
                            mClients.put(msg.replyTo, cInfo);
                        } else {
                        } else {
                            Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
                            Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
@@ -104,13 +145,102 @@ public class NsdService extends INsdManager.Stub {
                            if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
                            if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
                        }
                        }
                        mClients.remove(msg.replyTo);
                        mClients.remove(msg.replyTo);
                    if (mClients.size() == 0) {
                        stopMDnsDaemon();
                    }
                        break;
                        break;
                    case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
                    case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
                        AsyncChannel ac = new AsyncChannel();
                        AsyncChannel ac = new AsyncChannel();
                    ac.connect(mContext, this, msg.replyTo);
                        ac.connect(mContext, getHandler(), msg.replyTo);
                        break;
                    case NsdManager.DISCOVER_SERVICES:
                        mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
                                NsdManager.BUSY);
                       break;
                    case NsdManager.STOP_DISCOVERY:
                            mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
                                    NsdManager.ERROR);
                        break;
                    case NsdManager.REGISTER_SERVICE:
                        mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
                                NsdManager.ERROR);
                        break;
                    case NsdManager.UNREGISTER_SERVICE:
                        mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
                                NsdManager.ERROR);
                        break;
                    case NsdManager.RESOLVE_SERVICE:
                        mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
                                NsdManager.ERROR);
                        break;
                    case NsdManager.STOP_RESOLVE:
                        mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED,
                                NsdManager.ERROR);
                        break;
                    default:
                        Slog.e(TAG, "Unhandled " + msg);
                        return NOT_HANDLED;
                }
                return HANDLED;
            }
        }

        class DisabledState extends State {
            @Override
            public void enter() {
                sendNsdStateChangeBroadcast(false);
            }

            @Override
            public boolean processMessage(Message msg) {
                switch (msg.what) {
                    case NsdManager.ENABLE:
                        transitionTo(mEnabledState);
                        break;
                    default:
                        return NOT_HANDLED;
                }
                return HANDLED;
            }
        }

        class EnabledState extends State {
            @Override
            public void enter() {
                sendNsdStateChangeBroadcast(true);
                if (mClients.size() > 0) {
                    startMDnsDaemon();
                }
            }

            @Override
            public void exit() {
                if (mClients.size() > 0) {
                    stopMDnsDaemon();
                }
            }

            @Override
            public boolean processMessage(Message msg) {
                ClientInfo clientInfo;
                DnsSdServiceInfo servInfo;
                boolean result = HANDLED;
                switch (msg.what) {
                  case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                        //First client
                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
                                mClients.size() == 0) {
                            startMDnsDaemon();
                        }
                        result = NOT_HANDLED;
                        break;
                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
                        //Last client
                        if (mClients.size() == 1) {
                            stopMDnsDaemon();
                        }
                        result = NOT_HANDLED;
                        break;
                    case NsdManager.DISABLE:
                        //TODO: cleanup clients
                        transitionTo(mDisabledState);
                        break;
                        break;
                    case NsdManager.DISCOVER_SERVICES:
                    case NsdManager.DISCOVER_SERVICES:
                        if (DBG) Slog.d(TAG, "Discover services");
                        if (DBG) Slog.d(TAG, "Discover services");
@@ -173,7 +303,8 @@ public class NsdService extends INsdManager.Stub {
                        int regId = msg.arg1;
                        int regId = msg.arg1;
                        if (clientInfo.mRegisteredIds.remove(new Integer(regId)) &&
                        if (clientInfo.mRegisteredIds.remove(new Integer(regId)) &&
                                unregisterService(regId)) {
                                unregisterService(regId)) {
                        mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
                            mReplyChannel.replyToMessage(msg,
                                    NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
                        } else {
                        } else {
                            mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
                            mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
                                    NsdManager.ERROR);
                                    NsdManager.ERROR);
@@ -219,39 +350,69 @@ public class NsdService extends INsdManager.Stub {
                        }
                        }
                        break;
                        break;
                    default:
                    default:
                    Slog.d(TAG, "NsdServicehandler.handleMessage ignoring msg=" + msg);
                        result = NOT_HANDLED;
                        break;
                        break;
                }
                }
                return result;
            }
       }
       }
    }
    }
    private AsyncServiceHandler mAsyncServiceHandler;


    private NativeDaemonConnector mNativeConnector;
    private NativeDaemonConnector mNativeConnector;
    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);


    private NsdService(Context context) {
    private NsdService(Context context) {
        mContext = context;
        mContext = context;

        mContentResolver = context.getContentResolver();
        HandlerThread nsdThread = new HandlerThread("NsdService");
        nsdThread.start();
        mAsyncServiceHandler = new AsyncServiceHandler(nsdThread.getLooper());


        mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
        mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
                MDNS_TAG, 25);
                MDNS_TAG, 25);

        mNsdStateMachine = new NsdStateMachine(TAG);
        mNsdStateMachine.start();

        Thread th = new Thread(mNativeConnector, MDNS_TAG);
        Thread th = new Thread(mNativeConnector, MDNS_TAG);
        th.start();
        th.start();
    }
    }


    public static NsdService create(Context context) throws InterruptedException {
    public static NsdService create(Context context) throws InterruptedException {
        NsdService service = new NsdService(context);
        NsdService service = new NsdService(context);
        /* service.mNativeDaemonConnected.await(); */
        service.mNativeDaemonConnected.await();
        return service;
        return service;
    }
    }


    public Messenger getMessenger() {
    public Messenger getMessenger() {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
            "NsdService");
            "NsdService");
        return new Messenger(mAsyncServiceHandler);
        return new Messenger(mNsdStateMachine.getHandler());
    }

    public void setEnabled(boolean enable) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
                "NsdService");
        Settings.Secure.putInt(mContentResolver, Settings.Secure.NSD_ON, enable ? 1 : 0);
        if (enable) {
            mNsdStateMachine.sendMessage(NsdManager.ENABLE);
        } else {
            mNsdStateMachine.sendMessage(NsdManager.DISABLE);
        }
    }

    private void sendNsdStateChangeBroadcast(boolean enabled) {
        final Intent intent = new Intent(NsdManager.NSD_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        if (enabled) {
            intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
        } else {
            intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
        }
        mContext.sendStickyBroadcast(intent);
    }

    private boolean isNsdEnabled() {
        boolean ret = Settings.Secure.getInt(mContentResolver, Settings.Secure.NSD_ON, 1) == 1;
        if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
        return ret;
    }
    }


    private int getUniqueId() {
    private int getUniqueId() {
@@ -522,7 +683,7 @@ public class NsdService extends INsdManager.Stub {
    }
    }


    @Override
    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
                != PackageManager.PERMISSION_GRANTED) {
            pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
            pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
@@ -531,7 +692,12 @@ public class NsdService extends INsdManager.Stub {
            return;
            return;
        }
        }


        pw.println("Internal state:");
        for (ClientInfo client : mClients.values()) {
            pw.println("Client Info");
            pw.println(client);
        }

        mNsdStateMachine.dump(fd, pw, args);
    }
    }


    private ClientInfo getClientByDiscovery(int discoveryId) {
    private ClientInfo getClientByDiscovery(int discoveryId) {
@@ -579,5 +745,19 @@ public class NsdService extends INsdManager.Stub {
            mDiscoveryId = mResolveId = INVALID_ID;
            mDiscoveryId = mResolveId = INVALID_ID;
            if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
            if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
        }
        }

        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("mChannel ").append(mChannel).append("\n");
            sb.append("mMessenger ").append(mMessenger).append("\n");
            sb.append("mDiscoveryId ").append(mDiscoveryId).append("\n");
            sb.append("mResolveId ").append(mResolveId).append("\n");
            sb.append("mResolvedService ").append(mResolvedService).append("\n");
            for(int regId : mRegisteredIds) {
                sb.append("regId ").append(regId).append("\n");
            }
            return sb.toString();
        }
    }
    }
}
}