summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2012-07-26 18:32:30 -0700
committerJeff Sharkey <jsharkey@android.com>2012-08-08 16:23:41 -0700
commitfb878b66b9456f8fee2bcb1076263852d207949d (patch)
tree2f2d3f1de5c8de8e04c4a84d5c443471837adf58
parent088f29f55eebc6862a4cb5dddeaefacf24f74d95 (diff)
downloadframeworks_base-fb878b66b9456f8fee2bcb1076263852d207949d.zip
frameworks_base-fb878b66b9456f8fee2bcb1076263852d207949d.tar.gz
frameworks_base-fb878b66b9456f8fee2bcb1076263852d207949d.tar.bz2
Isolate NetworkStateTracker creation, test.
Change ConnectivityService to use a factory when creating NetworkStateTrackers, which gives us a good place to inject mocks for testing. Add initial tests to verify that network routes are added and removed as networks changed. Change-Id: I11cbc61a84c2ed4afa2670036295b1494eab26e1
-rw-r--r--services/java/com/android/server/ConnectivityService.java172
-rw-r--r--services/tests/servicestests/Android.mk3
-rw-r--r--services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java224
3 files changed, 328 insertions, 71 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index ad63424..206be68 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -20,6 +20,13 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
+import static android.net.ConnectivityManager.TYPE_DUMMY;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -86,14 +93,13 @@ import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
+
import dalvik.system.DexClassLoader;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.InvocationTargetException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -317,6 +323,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public ConnectivityService(Context context, INetworkManagementService netd,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
+ // Currently, omitting a NetworkFactory will create one internally
+ // TODO: create here when we have cleaner WiMAX support
+ this(context, netd, statsService, policyManager, null);
+ }
+
+ public ConnectivityService(Context context, INetworkManagementService netd,
+ INetworkStatsService statsService, INetworkPolicyManager policyManager,
+ NetworkFactory netFactory) {
if (DBG) log("ConnectivityService starting up");
HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
@@ -324,6 +338,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mHandler = new InternalHandler(handlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
+ if (netFactory == null) {
+ netFactory = new DefaultNetworkFactory(context, mTrackerHandler);
+ }
+
// setup our unique device name
if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
String id = Settings.Secure.getString(context.getContentResolver(),
@@ -462,59 +480,27 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mTestMode = SystemProperties.get("cm.test.mode").equals("true")
&& SystemProperties.get("ro.build.type").equals("eng");
- /*
- * Create the network state trackers for Wi-Fi and mobile
- * data. Maybe this could be done with a factory class,
- * but it's not clear that it's worth it, given that
- * the number of different network types is not going
- * to change very often.
- */
- for (int netType : mPriorityList) {
- switch (mNetConfigs[netType].radio) {
- case ConnectivityManager.TYPE_WIFI:
- mNetTrackers[netType] = new WifiStateTracker(
- netType, mNetConfigs[netType].name);
- mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
- break;
- case ConnectivityManager.TYPE_MOBILE:
- mNetTrackers[netType] = new MobileDataStateTracker(netType,
- mNetConfigs[netType].name);
- mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
- break;
- case ConnectivityManager.TYPE_DUMMY:
- mNetTrackers[netType] = new DummyDataStateTracker(netType,
- mNetConfigs[netType].name);
- mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
- break;
- case ConnectivityManager.TYPE_BLUETOOTH:
- mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
- mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
- break;
- case ConnectivityManager.TYPE_WIMAX:
- mNetTrackers[netType] = makeWimaxStateTracker();
- if (mNetTrackers[netType]!= null) {
- mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
- }
- break;
- case ConnectivityManager.TYPE_ETHERNET:
- mNetTrackers[netType] = EthernetDataTracker.getInstance();
- mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
- break;
- default:
- loge("Trying to create a DataStateTracker for an unknown radio type " +
- mNetConfigs[netType].radio);
+
+ // Create and start trackers for hard-coded networks
+ for (int targetNetworkType : mPriorityList) {
+ final NetworkConfig config = mNetConfigs[targetNetworkType];
+ final NetworkStateTracker tracker;
+ try {
+ tracker = netFactory.createTracker(targetNetworkType, config);
+ mNetTrackers[targetNetworkType] = tracker;
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
+ + " tracker: " + e);
continue;
}
- mCurrentLinkProperties[netType] = null;
- if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) {
- mNetTrackers[netType].reconnect();
+
+ tracker.startMonitoring(context, mTrackerHandler);
+ if (config.isDefault()) {
+ tracker.reconnect();
}
}
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
-
- mTethering = new Tethering(mContext, nmService, statsService, this, mHandler.getLooper());
+ mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
mTethering.getTetherableWifiRegexs().length != 0 ||
mTethering.getTetherableBluetoothRegexs().length != 0) &&
@@ -523,9 +509,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mVpn = new Vpn(mContext, new VpnCallback());
try {
- nmService.registerObserver(mTethering);
- nmService.registerObserver(mVpn);
- nmService.registerObserver(mDataActivityObserver);
+ mNetd.registerObserver(mTethering);
+ mNetd.registerObserver(mVpn);
+ mNetd.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
loge("Error registering observer :" + e);
}
@@ -540,7 +526,53 @@ public class ConnectivityService extends IConnectivityManager.Stub {
loadGlobalProxy();
}
- private NetworkStateTracker makeWimaxStateTracker() {
+ /**
+ * Factory that creates {@link NetworkStateTracker} instances using given
+ * {@link NetworkConfig}.
+ */
+ public interface NetworkFactory {
+ public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config);
+ }
+
+ private static class DefaultNetworkFactory implements NetworkFactory {
+ private final Context mContext;
+ private final Handler mTrackerHandler;
+
+ public DefaultNetworkFactory(Context context, Handler trackerHandler) {
+ mContext = context;
+ mTrackerHandler = trackerHandler;
+ }
+
+ @Override
+ public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
+ switch (config.radio) {
+ case TYPE_WIFI:
+ return new WifiStateTracker(targetNetworkType, config.name);
+ case TYPE_MOBILE:
+ return new MobileDataStateTracker(targetNetworkType, config.name);
+ case TYPE_DUMMY:
+ return new DummyDataStateTracker(targetNetworkType, config.name);
+ case TYPE_BLUETOOTH:
+ return BluetoothTetheringDataTracker.getInstance();
+ case TYPE_WIMAX:
+ return makeWimaxStateTracker(mContext, mTrackerHandler);
+ case TYPE_ETHERNET:
+ return EthernetDataTracker.getInstance();
+ default:
+ throw new IllegalArgumentException(
+ "Trying to create a NetworkStateTracker for an unknown radio type: "
+ + config.radio);
+ }
+ }
+ }
+
+ /**
+ * Loads external WiMAX library and registers as system service, returning a
+ * {@link NetworkStateTracker} for WiMAX. Caller is still responsible for
+ * invoking {@link NetworkStateTracker#startMonitoring(Context, Handler)}.
+ */
+ private static NetworkStateTracker makeWimaxStateTracker(
+ Context context, Handler trackerHandler) {
// Initialize Wimax
DexClassLoader wimaxClassLoader;
Class wimaxStateTrackerClass = null;
@@ -554,25 +586,25 @@ public class ConnectivityService extends IConnectivityManager.Stub {
NetworkStateTracker wimaxStateTracker = null;
- boolean isWimaxEnabled = mContext.getResources().getBoolean(
+ boolean isWimaxEnabled = context.getResources().getBoolean(
com.android.internal.R.bool.config_wimaxEnabled);
if (isWimaxEnabled) {
try {
- wimaxJarLocation = mContext.getResources().getString(
+ wimaxJarLocation = context.getResources().getString(
com.android.internal.R.string.config_wimaxServiceJarLocation);
- wimaxLibLocation = mContext.getResources().getString(
+ wimaxLibLocation = context.getResources().getString(
com.android.internal.R.string.config_wimaxNativeLibLocation);
- wimaxManagerClassName = mContext.getResources().getString(
+ wimaxManagerClassName = context.getResources().getString(
com.android.internal.R.string.config_wimaxManagerClassname);
- wimaxServiceClassName = mContext.getResources().getString(
+ wimaxServiceClassName = context.getResources().getString(
com.android.internal.R.string.config_wimaxServiceClassname);
- wimaxStateTrackerClassName = mContext.getResources().getString(
+ wimaxStateTrackerClassName = context.getResources().getString(
com.android.internal.R.string.config_wimaxStateTrackerClassname);
log("wimaxJarLocation: " + wimaxJarLocation);
wimaxClassLoader = new DexClassLoader(wimaxJarLocation,
- new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
+ new ContextWrapper(context).getCacheDir().getAbsolutePath(),
wimaxLibLocation, ClassLoader.getSystemClassLoader());
try {
@@ -593,13 +625,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
(new Class[] {Context.class, Handler.class});
- wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,
- mTrackerHandler);
+ wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance(
+ context, trackerHandler);
Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
(new Class[] {Context.class, wimaxStateTrackerClass});
wmxSrvConst.setAccessible(true);
- IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(mContext, wimaxStateTracker);
+ IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker);
wmxSrvConst.setAccessible(false);
ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
@@ -1873,6 +1905,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// snapshot isFailover, because sendConnectedBroadcast() resets it
boolean isFailover = info.isFailover();
final NetworkStateTracker thisNet = mNetTrackers[type];
+ final String thisIface = thisNet.getLinkProperties().getInterfaceName();
// if this is a default net and other default is running
// kill the one not preferred
@@ -1931,10 +1964,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
// notify battery stats service about this network
- final String iface = thisNet.getLinkProperties().getInterfaceName();
- if (iface != null) {
+ if (thisIface != null) {
try {
- BatteryStatsService.getService().noteNetworkInterfaceType(iface, type);
+ BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, type);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
@@ -2924,11 +2956,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- private void log(String s) {
+ private static void log(String s) {
Slog.d(TAG, s);
}
- private void loge(String s) {
+ private static void loge(String s) {
Slog.e(TAG, s);
}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 295f324..81a2c14 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -9,7 +9,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
easymocklib \
- guava
+ guava \
+ littlemock
LOCAL_JAVA_LIBRARIES := android.test.runner services
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
new file mode 100644
index 0000000..93ea6a2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -0,0 +1,224 @@
+/*
+ * 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 com.android.server;
+
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.getNetworkTypeName;
+import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED;
+import static com.google.testing.littlemock.LittleMock.anyInt;
+import static com.google.testing.littlemock.LittleMock.createCaptor;
+import static com.google.testing.littlemock.LittleMock.doNothing;
+import static com.google.testing.littlemock.LittleMock.doReturn;
+import static com.google.testing.littlemock.LittleMock.doThrow;
+import static com.google.testing.littlemock.LittleMock.eq;
+import static com.google.testing.littlemock.LittleMock.isA;
+import static com.google.testing.littlemock.LittleMock.mock;
+import static com.google.testing.littlemock.LittleMock.reset;
+import static com.google.testing.littlemock.LittleMock.verify;
+
+import android.content.Context;
+import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
+import android.net.LinkProperties;
+import android.net.NetworkConfig;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkStateTracker;
+import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.INetworkManagementService;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.util.LogPrinter;
+
+import com.google.testing.littlemock.ArgumentCaptor;
+
+import java.net.InetAddress;
+import java.util.concurrent.Future;
+
+/**
+ * Tests for {@link ConnectivityService}.
+ */
+@LargeTest
+public class ConnectivityServiceTest extends AndroidTestCase {
+ private static final String TAG = "ConnectivityServiceTest";
+
+ private static final String MOBILE_IFACE = "rmnet3";
+ private static final String WIFI_IFACE = "wlan6";
+
+ private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33"));
+ private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33"));
+
+ private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute(
+ parse("192.168.0.66"), parse("192.168.0.1"));
+ private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute(
+ parse("fd00::66"), parse("fd00::"));
+
+ private INetworkManagementService mNetManager;
+ private INetworkStatsService mStatsService;
+ private INetworkPolicyManager mPolicyService;
+ private ConnectivityService.NetworkFactory mNetFactory;
+
+ private BroadcastInterceptingContext mServiceContext;
+ private ConnectivityService mService;
+
+ private MockNetwork mMobile;
+ private MockNetwork mWifi;
+
+ private Handler mTrackerHandler;
+
+ private static class MockNetwork {
+ public NetworkStateTracker tracker;
+ public NetworkInfo info;
+ public LinkProperties link;
+
+ public MockNetwork(int type) {
+ tracker = mock(NetworkStateTracker.class);
+ info = new NetworkInfo(type, -1, getNetworkTypeName(type), null);
+ link = new LinkProperties();
+ }
+
+ public void doReturnDefaults() {
+ // TODO: eventually CS should make defensive copies
+ doReturn(new NetworkInfo(info)).when(tracker).getNetworkInfo();
+ doReturn(new LinkProperties(link)).when(tracker).getLinkProperties();
+
+ // fallback to default TCP buffers
+ doReturn("").when(tracker).getTcpBufferSizesPropName();
+ }
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mServiceContext = new BroadcastInterceptingContext(getContext());
+
+ mNetManager = mock(INetworkManagementService.class);
+ mStatsService = mock(INetworkStatsService.class);
+ mPolicyService = mock(INetworkPolicyManager.class);
+ mNetFactory = mock(ConnectivityService.NetworkFactory.class);
+
+ mMobile = new MockNetwork(TYPE_MOBILE);
+ mWifi = new MockNetwork(TYPE_WIFI);
+
+ // omit most network trackers
+ doThrow(new IllegalArgumentException("Not supported in test environment"))
+ .when(mNetFactory).createTracker(anyInt(), isA(NetworkConfig.class));
+
+ doReturn(mMobile.tracker)
+ .when(mNetFactory).createTracker(eq(TYPE_MOBILE), isA(NetworkConfig.class));
+ doReturn(mWifi.tracker)
+ .when(mNetFactory).createTracker(eq(TYPE_WIFI), isA(NetworkConfig.class));
+
+ final ArgumentCaptor<Handler> trackerHandler = createCaptor();
+ doNothing().when(mMobile.tracker)
+ .startMonitoring(isA(Context.class), trackerHandler.capture());
+
+ mService = new ConnectivityService(
+ mServiceContext, mNetManager, mStatsService, mPolicyService, mNetFactory);
+ mService.systemReady();
+
+ mTrackerHandler = trackerHandler.getValue();
+ mTrackerHandler.getLooper().setMessageLogging(new LogPrinter(Log.INFO, TAG));
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testMobileConnectedAddedRoutes() throws Exception {
+ Future<?> nextConnBroadcast;
+
+ // bring up mobile network
+ mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
+ mMobile.link.setInterfaceName(MOBILE_IFACE);
+ mMobile.link.addRoute(MOBILE_ROUTE_V4);
+ mMobile.link.addRoute(MOBILE_ROUTE_V6);
+ mMobile.doReturnDefaults();
+
+ nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+ mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
+ nextConnBroadcast.get();
+
+ // verify that both routes were added and DNS was flushed
+ verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
+ verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
+ verify(mNetManager).flushInterfaceDnsCache(MOBILE_IFACE);
+
+ }
+
+ public void testMobileWifiHandoff() throws Exception {
+ Future<?> nextConnBroadcast;
+
+ // bring up mobile network
+ mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
+ mMobile.link.setInterfaceName(MOBILE_IFACE);
+ mMobile.link.addRoute(MOBILE_ROUTE_V4);
+ mMobile.link.addRoute(MOBILE_ROUTE_V6);
+ mMobile.doReturnDefaults();
+
+ nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+ mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
+ nextConnBroadcast.get();
+
+ reset(mNetManager);
+
+ // now bring up wifi network
+ mWifi.info.setDetailedState(DetailedState.CONNECTED, null, null);
+ mWifi.link.setInterfaceName(WIFI_IFACE);
+ mWifi.link.addRoute(WIFI_ROUTE_V4);
+ mWifi.link.addRoute(WIFI_ROUTE_V6);
+ mWifi.doReturnDefaults();
+
+ // expect that mobile will be torn down
+ doReturn(true).when(mMobile.tracker).teardown();
+
+ nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+ mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mWifi.info).sendToTarget();
+ nextConnBroadcast.get();
+
+ // verify that wifi routes added, and teardown requested
+ verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V4));
+ verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V6));
+ verify(mNetManager).flushInterfaceDnsCache(WIFI_IFACE);
+ verify(mMobile.tracker).teardown();
+
+ reset(mNetManager, mMobile.tracker);
+
+ // tear down mobile network, as requested
+ mMobile.info.setDetailedState(DetailedState.DISCONNECTED, null, null);
+ mMobile.link.clear();
+ mMobile.doReturnDefaults();
+
+ nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+ mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
+ nextConnBroadcast.get();
+
+ verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
+ verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
+
+ }
+
+ private static InetAddress parse(String addr) {
+ return InetAddress.parseNumericAddress(addr);
+ }
+}