OSDN Git Service

Cleanup NetworkManagementService for Netd commnads binder migrartion
authorLuke Huang <huangluke@google.com>
Sat, 16 Mar 2019 13:21:16 +0000 (21:21 +0800)
committerLuke Huang <huangluke@google.com>
Wed, 20 Mar 2019 12:02:24 +0000 (20:02 +0800)
remove dead code used for netd UNIX sokcet

Bug: 65862741
Test: atest NetworkManagementServiceTest FrameworksNetTests
Change-Id: I5db61cb86325b71ac8a8fce7b15dbf569abc5935

core/java/android/os/INetworkManagementService.aidl
services/core/java/com/android/server/NetworkManagementService.java
tests/net/java/com/android/server/NetworkManagementServiceTest.java

index f62a999..6536fc9 100644 (file)
@@ -242,27 +242,6 @@ interface INetworkManagementService
     void tetherLimitReached(ITetheringStatsProvider provider);
 
     /**
-     ** PPPD
-     **/
-
-    /**
-     * Returns the list of currently known TTY devices on the system
-     */
-    String[] listTtys();
-
-    /**
-     * Attaches a PPP server daemon to the specified TTY with the specified
-     * local/remote addresses.
-     */
-    void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
-            String dns2Addr);
-
-    /**
-     * Detaches a PPP server daemon from the specified TTY.
-     */
-    void detachPppd(String tty);
-
-    /**
      ** DATA USAGE RELATED
      **/
 
index a9645c4..f75d04c 100644 (file)
@@ -39,7 +39,6 @@ import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
 
-import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
 import android.annotation.NonNull;
@@ -69,7 +68,6 @@ import android.os.Handler;
 import android.os.IBinder;
 import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -109,13 +107,11 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
 /**
  * @hide
  */
-public class NetworkManagementService extends INetworkManagementService.Stub
-        implements Watchdog.Monitor {
+public class NetworkManagementService extends INetworkManagementService.Stub {
 
     /**
      * Helper class that encapsulates NetworkManagementService dependencies and makes them
@@ -135,8 +131,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
     private static final String TAG = "NetworkManagement";
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final String NETD_TAG = "NetdConnector";
-    static final String NETD_SERVICE_NAME = "netd";
 
     private static final int MAX_UID_RANGES_PER_COMMAND = 10;
 
@@ -146,44 +140,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
      */
     public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
 
-    static class NetdResponseCode {
-        /* Keep in sync with system/netd/server/ResponseCode.h */
-        public static final int InterfaceListResult       = 110;
-        public static final int TetherInterfaceListResult = 111;
-        public static final int TetherDnsFwdTgtListResult = 112;
-        public static final int TtyListResult             = 113;
-        public static final int TetheringStatsListResult  = 114;
-
-        public static final int TetherStatusResult        = 210;
-        public static final int IpFwdStatusResult         = 211;
-        public static final int InterfaceGetCfgResult     = 213;
-        public static final int SoftapStatusResult        = 214;
-        public static final int InterfaceRxCounterResult  = 216;
-        public static final int InterfaceTxCounterResult  = 217;
-        public static final int QuotaCounterResult        = 220;
-        public static final int TetheringStatsResult      = 221;
-        public static final int DnsProxyQueryResult       = 222;
-        public static final int ClatdStatusResult         = 223;
-
-        public static final int InterfaceChange           = 600;
-        public static final int BandwidthControl          = 601;
-        public static final int InterfaceClassActivity    = 613;
-        public static final int InterfaceAddressChange    = 614;
-        public static final int InterfaceDnsServerInfo    = 615;
-        public static final int RouteChange               = 616;
-        public static final int StrictCleartext           = 617;
-    }
-
-    /**
-     * String indicating a softap command.
-     */
-    static final String SOFT_AP_COMMAND = "softap";
-
-    /**
-     * String passed back to netd connector indicating softap command success.
-     */
-    static final String SOFT_AP_COMMAND_SUCCESS = "Ok";
-
     static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
 
     static final boolean MODIFY_OPERATION_ADD = true;
@@ -194,12 +150,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
      */
     private final Context mContext;
 
-    /**
-     * connector object for communicating with netd
-     */
-    private final NativeDaemonConnector mConnector;
-
-    private final Handler mFgHandler;
     private final Handler mDaemonHandler;
 
     private final SystemServices mServices;
@@ -210,9 +160,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
     private IBatteryStats mBatteryStats;
 
-    private final Thread mThread;
-    private CountDownLatch mConnectedSignal = new CountDownLatch(1);
-
     private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
             new RemoteCallbackList<>();
 
@@ -304,32 +251,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub
      * @param context  Binder context for this service
      */
     private NetworkManagementService(
-            Context context, String socket, SystemServices services) {
+            Context context, SystemServices services) {
         mContext = context;
         mServices = services;
 
-        // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
-        mFgHandler = new Handler(FgThread.get().getLooper());
-
-        // Don't need this wake lock, since we now have a time stamp for when
-        // the network actually went inactive.  (It might be nice to still do this,
-        // but I don't want to do it through the power manager because that pollutes the
-        // battery stats history with pointless noise.)
-        //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
-
-        mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
-                FgThread.get().getLooper());
-        mThread = new Thread(mConnector, NETD_TAG);
-
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
         mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
 
-        // Add ourself to the Watchdog monitors.
-        Watchdog.getInstance().addMonitor(this);
-
         mServices.registerLocalService(new LocalService());
 
         synchronized (mTetheringStatsProviders) {
@@ -339,25 +268,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
     @VisibleForTesting
     NetworkManagementService() {
-        mConnector = null;
         mContext = null;
         mDaemonHandler = null;
-        mFgHandler = null;
-        mThread = null;
         mServices = null;
         mNetdUnsolicitedEventListener = null;
     }
 
-    static NetworkManagementService create(Context context, String socket, SystemServices services)
+    static NetworkManagementService create(Context context, SystemServices services)
             throws InterruptedException {
         final NetworkManagementService service =
-                new NetworkManagementService(context, socket, services);
-        final CountDownLatch connectedSignal = service.mConnectedSignal;
+                new NetworkManagementService(context, services);
         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
-        service.mThread.start();
-        if (DBG) Slog.d(TAG, "Awaiting socket connection");
-        connectedSignal.await();
-        if (DBG) Slog.d(TAG, "Connected");
         if (DBG) Slog.d(TAG, "Connecting native netd service");
         service.connectNativeNetdService();
         if (DBG) Slog.d(TAG, "Connected");
@@ -365,7 +286,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     }
 
     public static NetworkManagementService create(Context context) throws InterruptedException {
-        return create(context, NETD_SERVICE_NAME, new SystemServices());
+        return create(context, new SystemServices());
     }
 
     public void systemReady() {
@@ -805,212 +726,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     }
 
     //
-    // Netd Callback handling
-    //
-
-    private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
-        @Override
-        public void onDaemonConnected() {
-            Slog.i(TAG, "onDaemonConnected()");
-            // event is dispatched from internal NDC thread, so we prepare the
-            // daemon back on main thread.
-            if (mConnectedSignal != null) {
-                // The system is booting and we're connecting to netd for the first time.
-                mConnectedSignal.countDown();
-                mConnectedSignal = null;
-            } else {
-                // We're reconnecting to netd after the socket connection
-                // was interrupted (e.g., if it crashed).
-                mFgHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        connectNativeNetdService();
-                        prepareNativeDaemon();
-                    }
-                });
-            }
-        }
-
-        @Override
-        public boolean onCheckHoldWakeLock(int code) {
-            return code == NetdResponseCode.InterfaceClassActivity;
-        }
-
-        @Override
-        public boolean onEvent(int code, String raw, String[] cooked) {
-            String errorMessage = String.format("Invalid event from daemon (%s)", raw);
-            switch (code) {
-            case NetdResponseCode.InterfaceChange:
-                    /*
-                     * a network interface change occured
-                     * Format: "NNN Iface added <name>"
-                     *         "NNN Iface removed <name>"
-                     *         "NNN Iface changed <name> <up/down>"
-                     *         "NNN Iface linkstatus <name> <up/down>"
-                     */
-                    if (cooked.length < 4 || !cooked[1].equals("Iface")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-                    if (cooked[2].equals("added")) {
-                        notifyInterfaceAdded(cooked[3]);
-                        return true;
-                    } else if (cooked[2].equals("removed")) {
-                        notifyInterfaceRemoved(cooked[3]);
-                        return true;
-                    } else if (cooked[2].equals("changed") && cooked.length == 5) {
-                        notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
-                        return true;
-                    } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
-                        notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
-                        return true;
-                    }
-                    throw new IllegalStateException(errorMessage);
-                    // break;
-            case NetdResponseCode.BandwidthControl:
-                    /*
-                     * Bandwidth control needs some attention
-                     * Format: "NNN limit alert <alertName> <ifaceName>"
-                     */
-                    if (cooked.length < 5 || !cooked[1].equals("limit")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-                    if (cooked[2].equals("alert")) {
-                        notifyLimitReached(cooked[3], cooked[4]);
-                        return true;
-                    }
-                    throw new IllegalStateException(errorMessage);
-                    // break;
-            case NetdResponseCode.InterfaceClassActivity:
-                    /*
-                     * An network interface class state changed (active/idle)
-                     * Format: "NNN IfaceClass <active/idle> <label>"
-                     */
-                    if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-                    long timestampNanos = 0;
-                    int processUid = -1;
-                    if (cooked.length >= 5) {
-                        try {
-                            timestampNanos = Long.parseLong(cooked[4]);
-                            if (cooked.length == 6) {
-                                processUid = Integer.parseInt(cooked[5]);
-                            }
-                        } catch(NumberFormatException ne) {}
-                    } else {
-                        timestampNanos = SystemClock.elapsedRealtimeNanos();
-                    }
-                    boolean isActive = cooked[2].equals("active");
-                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
-                            isActive, timestampNanos, processUid, false);
-                    return true;
-                    // break;
-            case NetdResponseCode.InterfaceAddressChange:
-                    /*
-                     * A network address change occurred
-                     * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
-                     *         "NNN Address removed <addr> <iface> <flags> <scope>"
-                     */
-                    if (cooked.length < 7 || !cooked[1].equals("Address")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-
-                    String iface = cooked[4];
-                    LinkAddress address;
-                    try {
-                        int flags = Integer.parseInt(cooked[5]);
-                        int scope = Integer.parseInt(cooked[6]);
-                        address = new LinkAddress(cooked[3], flags, scope);
-                    } catch(NumberFormatException e) {     // Non-numeric lifetime or scope.
-                        throw new IllegalStateException(errorMessage, e);
-                    } catch(IllegalArgumentException e) {  // Malformed/invalid IP address.
-                        throw new IllegalStateException(errorMessage, e);
-                    }
-
-                    if (cooked[2].equals("updated")) {
-                        notifyAddressUpdated(iface, address);
-                    } else {
-                        notifyAddressRemoved(iface, address);
-                    }
-                    return true;
-                    // break;
-            case NetdResponseCode.InterfaceDnsServerInfo:
-                    /*
-                     * Information about available DNS servers has been received.
-                     * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
-                     */
-                    long lifetime;  // Actually a 32-bit unsigned integer.
-
-                    if (cooked.length == 6 &&
-                        cooked[1].equals("DnsInfo") &&
-                        cooked[2].equals("servers")) {
-                        try {
-                            lifetime = Long.parseLong(cooked[4]);
-                        } catch (NumberFormatException e) {
-                            throw new IllegalStateException(errorMessage);
-                        }
-                        String[] servers = cooked[5].split(",");
-                        notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
-                    }
-                    return true;
-                    // break;
-            case NetdResponseCode.RouteChange:
-                    /*
-                     * A route has been updated or removed.
-                     * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
-                     */
-                    if (!cooked[1].equals("Route") || cooked.length < 6) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-
-                    String via = null;
-                    String dev = null;
-                    boolean valid = true;
-                    for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
-                        if (cooked[i].equals("dev")) {
-                            if (dev == null) {
-                                dev = cooked[i+1];
-                            } else {
-                                valid = false;  // Duplicate interface.
-                            }
-                        } else if (cooked[i].equals("via")) {
-                            if (via == null) {
-                                via = cooked[i+1];
-                            } else {
-                                valid = false;  // Duplicate gateway.
-                            }
-                        } else {
-                            valid = false;      // Unknown syntax.
-                        }
-                    }
-                    if (valid) {
-                        try {
-                            // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
-                            InetAddress gateway = null;
-                            if (via != null) gateway = InetAddress.parseNumericAddress(via);
-                            RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
-                            notifyRouteChange(cooked[2].equals("updated"), route);
-                            return true;
-                        } catch (IllegalArgumentException e) {}
-                    }
-                    throw new IllegalStateException(errorMessage);
-                    // break;
-            case NetdResponseCode.StrictCleartext:
-                final int uid = Integer.parseInt(cooked[1]);
-                final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]);
-                try {
-                    ActivityManager.getService().notifyCleartextNetwork(uid, firstPacket);
-                } catch (RemoteException ignored) {
-                }
-                break;
-            default: break;
-            }
-            return false;
-        }
-    }
-
-
-    //
     // INetworkManagementService members
     //
     @Override
@@ -1392,42 +1107,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     }
 
     @Override
-    public String[] listTtys() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            return NativeDaemonEvent.filterMessageList(
-                    mConnector.executeForList("list_ttys"), TtyListResult);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void attachPppd(
-            String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("pppd", "attach", tty,
-                    NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
-                    NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
-                    NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
-                    NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void detachPppd(String tty) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("pppd", "detach", tty);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
     public void addIdleTimer(String iface, int timeout, final int type) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
@@ -2232,22 +1911,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
         }
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public void monitor() {
-        if (mConnector != null) {
-            mConnector.monitor();
-        }
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        pw.println("NetworkManagementService NativeDaemonConnector Log:");
-        mConnector.dump(fd, pw, args);
-        pw.println();
-
         pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
                 pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
         pw.print("mNetworkActive="); pw.println(mNetworkActive);
index 6fb3225..968b307 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -23,11 +24,11 @@ import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.INetd;
+import android.net.INetdUnsolicitedEventListener;
 import android.net.LinkAddress;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.IBinder;
@@ -43,12 +44,11 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.io.IOException;
-import java.io.OutputStream;
-
 /**
  * Tests for {@link NetworkManagementService}.
  */
@@ -56,16 +56,16 @@ import java.io.OutputStream;
 @SmallTest
 public class NetworkManagementServiceTest {
 
-    private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest";
     private NetworkManagementService mNMService;
-    private LocalServerSocket mServerSocket;
-    private LocalSocket mSocket;
-    private OutputStream mOutputStream;
 
     @Mock private Context mContext;
     @Mock private IBatteryStats.Stub mBatteryStatsService;
     @Mock private INetd.Stub mNetdService;
 
+    @NonNull
+    @Captor
+    private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
+
     private final SystemServices mServices = new SystemServices() {
         @Override
         public IBinder getService(String name) {
@@ -88,32 +88,15 @@ public class NetworkManagementServiceTest {
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-
-        // Set up a sheltered test environment.
-        mServerSocket = new LocalServerSocket(SOCKET_NAME);
-
+        doNothing().when(mNetdService)
+                .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
         // Start the service and wait until it connects to our socket.
-        mNMService = NetworkManagementService.create(mContext, SOCKET_NAME, mServices);
-        mSocket = mServerSocket.accept();
-        mOutputStream = mSocket.getOutputStream();
+        mNMService = NetworkManagementService.create(mContext, mServices);
     }
 
     @After
     public void tearDown() throws Exception {
         mNMService.shutdown();
-        // Once NetworkManagementService#shutdown() actually does something and shutdowns
-        // the underlying NativeDaemonConnector, the block below should be uncommented.
-        // if (mOutputStream != null) mOutputStream.close();
-        // if (mSocket != null) mSocket.close();
-        // if (mServerSocket != null) mServerSocket.close();
-    }
-
-    /**
-     * Sends a message on the netd socket and gives the events some time to make it back.
-     */
-    private void sendMessage(String message) throws IOException {
-        // Strings are null-terminated, so add "\0" at the end.
-        mOutputStream.write((message + "\0").getBytes());
     }
 
     private static <T> T expectSoon(T mock) {
@@ -131,125 +114,78 @@ public class NetworkManagementServiceTest {
 
         // Forget everything that happened to the mock so far, so we can explicitly verify
         // everything that happens and does not happen to it from now on.
-        reset(observer);
 
-        // Now send NetworkManagementService messages and ensure that the observer methods are
-        // called. After every valid message we expect a callback soon after; to ensure that
+        INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
+        reset(observer);
+        // Now call unsolListener methods and ensure that the observer methods are
+        // called. After every method we expect a callback soon after; to ensure that
         // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
 
         /**
          * Interface changes.
          */
-        sendMessage("600 Iface added rmnet12");
+        unsolListener.onInterfaceAdded("rmnet12");
         expectSoon(observer).interfaceAdded("rmnet12");
 
-        sendMessage("600 Iface removed eth1");
+        unsolListener.onInterfaceRemoved("eth1");
         expectSoon(observer).interfaceRemoved("eth1");
 
-        sendMessage("607 Iface removed eth1");
-        // Invalid code.
-
-        sendMessage("600 Iface borked lo down");
-        // Invalid event.
-
-        sendMessage("600 Iface changed clat4 up again");
-        // Extra tokens.
-
-        sendMessage("600 Iface changed clat4 up");
+        unsolListener.onInterfaceChanged("clat4", true);
         expectSoon(observer).interfaceStatusChanged("clat4", true);
 
-        sendMessage("600 Iface linkstate rmnet0 down");
+        unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
         expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
 
-        sendMessage("600 IFACE linkstate clat4 up");
-        // Invalid group.
-
         /**
          * Bandwidth control events.
          */
-        sendMessage("601 limit alert data rmnet_usb0");
+        unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
         expectSoon(observer).limitReached("data", "rmnet_usb0");
 
-        sendMessage("601 invalid alert data rmnet0");
-        // Invalid group.
-
-        sendMessage("601 limit increased data rmnet0");
-        // Invalid event.
-
-
         /**
          * Interface class activity.
          */
-
-        sendMessage("613 IfaceClass active 1 1234 10012");
+        unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, 0);
         expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234);
 
-        sendMessage("613 IfaceClass idle 9 5678");
+        unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, 0);
         expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678);
 
-        sendMessage("613 IfaceClass reallyactive 9 4321");
+        unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, 0);
         expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321);
 
-        sendMessage("613 InterfaceClass reallyactive 1");
-        // Invalid group.
-
-
         /**
          * IP address changes.
          */
-        sendMessage("614 Address updated fe80::1/64 wlan0 128 253");
+        unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
         expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
 
-        // There is no "added", so we take this as "removed".
-        sendMessage("614 Address added fe80::1/64 wlan0 128 253");
+        unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
         expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
 
-        sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0");
+        unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
         expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
 
-        sendMessage("614 Address removed 2001:db8::1/64 wlan0 1");
-        // Not enough arguments.
-
-        sendMessage("666 Address removed 2001:db8::1/64 wlan0 1 0");
-        // Invalid code.
-
-
         /**
          * DNS information broadcasts.
          */
-        sendMessage("615 DnsInfo servers rmnet_usb0 3600 2001:db8::1");
+        unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
         expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
                 new String[]{"2001:db8::1"});
 
-        sendMessage("615 DnsInfo servers wlan0 14400 2001:db8::1,2001:db8::2");
+        unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
+                new String[]{"2001:db8::1", "2001:db8::2"});
         expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
                 new String[]{"2001:db8::1", "2001:db8::2"});
 
         // We don't check for negative lifetimes, only for parse errors.
-        sendMessage("615 DnsInfo servers wlan0 -3600 ::1");
+        unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
         expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
                 new String[]{"::1"});
 
-        sendMessage("615 DnsInfo servers wlan0 SIXHUNDRED ::1");
-        // Non-numeric lifetime.
-
-        sendMessage("615 DnsInfo servers wlan0 2001:db8::1");
-        // Missing lifetime.
-
-        sendMessage("615 DnsInfo servers wlan0 3600");
-        // No servers.
-
-        sendMessage("615 DnsInfo servers 3600 wlan0 2001:db8::1,2001:db8::2");
-        // Non-numeric lifetime.
-
-        sendMessage("615 DnsInfo wlan0 7200 2001:db8::1,2001:db8::2");
-        // Invalid tokens.
-
-        sendMessage("666 DnsInfo servers wlan0 5400 2001:db8::1");
-        // Invalid code.
-
         // No syntax checking on the addresses.
-        sendMessage("615 DnsInfo servers wlan0 600 ,::,,foo,::1,");
+        unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
+                new String[]{"", "::", "", "foo", "::1"});
         expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
                 new String[]{"", "::", "", "foo", "::1"});