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
This commit is contained in:
@@ -20,6 +20,13 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
|
|||||||
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
|
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
|
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.ConnectivityManager.isNetworkTypeValid;
|
||||||
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
|
||||||
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
|
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.android.server.net.BaseNetworkObserver;
|
||||||
import com.google.android.collect.Lists;
|
import com.google.android.collect.Lists;
|
||||||
import com.google.android.collect.Sets;
|
import com.google.android.collect.Sets;
|
||||||
|
|
||||||
import dalvik.system.DexClassLoader;
|
import dalvik.system.DexClassLoader;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.lang.reflect.Constructor;
|
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.Inet4Address;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
@@ -317,6 +323,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
|
|
||||||
public ConnectivityService(Context context, INetworkManagementService netd,
|
public ConnectivityService(Context context, INetworkManagementService netd,
|
||||||
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
|
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");
|
if (DBG) log("ConnectivityService starting up");
|
||||||
|
|
||||||
HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
|
HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
|
||||||
@@ -324,6 +338,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
mHandler = new InternalHandler(handlerThread.getLooper());
|
mHandler = new InternalHandler(handlerThread.getLooper());
|
||||||
mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
|
mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
|
||||||
|
|
||||||
|
if (netFactory == null) {
|
||||||
|
netFactory = new DefaultNetworkFactory(context, mTrackerHandler);
|
||||||
|
}
|
||||||
|
|
||||||
// setup our unique device name
|
// setup our unique device name
|
||||||
if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
|
if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
|
||||||
String id = Settings.Secure.getString(context.getContentResolver(),
|
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")
|
mTestMode = SystemProperties.get("cm.test.mode").equals("true")
|
||||||
&& SystemProperties.get("ro.build.type").equals("eng");
|
&& SystemProperties.get("ro.build.type").equals("eng");
|
||||||
/*
|
|
||||||
* Create the network state trackers for Wi-Fi and mobile
|
// Create and start trackers for hard-coded networks
|
||||||
* data. Maybe this could be done with a factory class,
|
for (int targetNetworkType : mPriorityList) {
|
||||||
* but it's not clear that it's worth it, given that
|
final NetworkConfig config = mNetConfigs[targetNetworkType];
|
||||||
* the number of different network types is not going
|
final NetworkStateTracker tracker;
|
||||||
* to change very often.
|
try {
|
||||||
*/
|
tracker = netFactory.createTracker(targetNetworkType, config);
|
||||||
for (int netType : mPriorityList) {
|
mNetTrackers[targetNetworkType] = tracker;
|
||||||
switch (mNetConfigs[netType].radio) {
|
} catch (IllegalArgumentException e) {
|
||||||
case ConnectivityManager.TYPE_WIFI:
|
Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
|
||||||
mNetTrackers[netType] = new WifiStateTracker(
|
+ " tracker: " + e);
|
||||||
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);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mCurrentLinkProperties[netType] = null;
|
|
||||||
if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) {
|
tracker.startMonitoring(context, mTrackerHandler);
|
||||||
mNetTrackers[netType].reconnect();
|
if (config.isDefault()) {
|
||||||
|
tracker.reconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
|
mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
|
||||||
INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
|
|
||||||
|
|
||||||
mTethering = new Tethering(mContext, nmService, statsService, this, mHandler.getLooper());
|
|
||||||
mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
|
mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
|
||||||
mTethering.getTetherableWifiRegexs().length != 0 ||
|
mTethering.getTetherableWifiRegexs().length != 0 ||
|
||||||
mTethering.getTetherableBluetoothRegexs().length != 0) &&
|
mTethering.getTetherableBluetoothRegexs().length != 0) &&
|
||||||
@@ -523,9 +509,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
mVpn = new Vpn(mContext, new VpnCallback());
|
mVpn = new Vpn(mContext, new VpnCallback());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
nmService.registerObserver(mTethering);
|
mNetd.registerObserver(mTethering);
|
||||||
nmService.registerObserver(mVpn);
|
mNetd.registerObserver(mVpn);
|
||||||
nmService.registerObserver(mDataActivityObserver);
|
mNetd.registerObserver(mDataActivityObserver);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
loge("Error registering observer :" + e);
|
loge("Error registering observer :" + e);
|
||||||
}
|
}
|
||||||
@@ -540,7 +526,53 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
loadGlobalProxy();
|
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
|
// Initialize Wimax
|
||||||
DexClassLoader wimaxClassLoader;
|
DexClassLoader wimaxClassLoader;
|
||||||
Class wimaxStateTrackerClass = null;
|
Class wimaxStateTrackerClass = null;
|
||||||
@@ -554,25 +586,25 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
|
|
||||||
NetworkStateTracker wimaxStateTracker = null;
|
NetworkStateTracker wimaxStateTracker = null;
|
||||||
|
|
||||||
boolean isWimaxEnabled = mContext.getResources().getBoolean(
|
boolean isWimaxEnabled = context.getResources().getBoolean(
|
||||||
com.android.internal.R.bool.config_wimaxEnabled);
|
com.android.internal.R.bool.config_wimaxEnabled);
|
||||||
|
|
||||||
if (isWimaxEnabled) {
|
if (isWimaxEnabled) {
|
||||||
try {
|
try {
|
||||||
wimaxJarLocation = mContext.getResources().getString(
|
wimaxJarLocation = context.getResources().getString(
|
||||||
com.android.internal.R.string.config_wimaxServiceJarLocation);
|
com.android.internal.R.string.config_wimaxServiceJarLocation);
|
||||||
wimaxLibLocation = mContext.getResources().getString(
|
wimaxLibLocation = context.getResources().getString(
|
||||||
com.android.internal.R.string.config_wimaxNativeLibLocation);
|
com.android.internal.R.string.config_wimaxNativeLibLocation);
|
||||||
wimaxManagerClassName = mContext.getResources().getString(
|
wimaxManagerClassName = context.getResources().getString(
|
||||||
com.android.internal.R.string.config_wimaxManagerClassname);
|
com.android.internal.R.string.config_wimaxManagerClassname);
|
||||||
wimaxServiceClassName = mContext.getResources().getString(
|
wimaxServiceClassName = context.getResources().getString(
|
||||||
com.android.internal.R.string.config_wimaxServiceClassname);
|
com.android.internal.R.string.config_wimaxServiceClassname);
|
||||||
wimaxStateTrackerClassName = mContext.getResources().getString(
|
wimaxStateTrackerClassName = context.getResources().getString(
|
||||||
com.android.internal.R.string.config_wimaxStateTrackerClassname);
|
com.android.internal.R.string.config_wimaxStateTrackerClassname);
|
||||||
|
|
||||||
log("wimaxJarLocation: " + wimaxJarLocation);
|
log("wimaxJarLocation: " + wimaxJarLocation);
|
||||||
wimaxClassLoader = new DexClassLoader(wimaxJarLocation,
|
wimaxClassLoader = new DexClassLoader(wimaxJarLocation,
|
||||||
new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
|
new ContextWrapper(context).getCacheDir().getAbsolutePath(),
|
||||||
wimaxLibLocation, ClassLoader.getSystemClassLoader());
|
wimaxLibLocation, ClassLoader.getSystemClassLoader());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -593,13 +625,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
|
|
||||||
Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
|
Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
|
||||||
(new Class[] {Context.class, Handler.class});
|
(new Class[] {Context.class, Handler.class});
|
||||||
wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,
|
wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance(
|
||||||
mTrackerHandler);
|
context, trackerHandler);
|
||||||
|
|
||||||
Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
|
Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
|
||||||
(new Class[] {Context.class, wimaxStateTrackerClass});
|
(new Class[] {Context.class, wimaxStateTrackerClass});
|
||||||
wmxSrvConst.setAccessible(true);
|
wmxSrvConst.setAccessible(true);
|
||||||
IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(mContext, wimaxStateTracker);
|
IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker);
|
||||||
wmxSrvConst.setAccessible(false);
|
wmxSrvConst.setAccessible(false);
|
||||||
|
|
||||||
ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
|
ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
|
||||||
@@ -1873,6 +1905,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
// snapshot isFailover, because sendConnectedBroadcast() resets it
|
// snapshot isFailover, because sendConnectedBroadcast() resets it
|
||||||
boolean isFailover = info.isFailover();
|
boolean isFailover = info.isFailover();
|
||||||
final NetworkStateTracker thisNet = mNetTrackers[type];
|
final NetworkStateTracker thisNet = mNetTrackers[type];
|
||||||
|
final String thisIface = thisNet.getLinkProperties().getInterfaceName();
|
||||||
|
|
||||||
// if this is a default net and other default is running
|
// if this is a default net and other default is running
|
||||||
// kill the one not preferred
|
// kill the one not preferred
|
||||||
@@ -1931,10 +1964,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
|
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
|
||||||
|
|
||||||
// notify battery stats service about this network
|
// notify battery stats service about this network
|
||||||
final String iface = thisNet.getLinkProperties().getInterfaceName();
|
if (thisIface != null) {
|
||||||
if (iface != null) {
|
|
||||||
try {
|
try {
|
||||||
BatteryStatsService.getService().noteNetworkInterfaceType(iface, type);
|
BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, type);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// ignored; service lives in system_server
|
// 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);
|
Slog.d(TAG, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loge(String s) {
|
private static void loge(String s) {
|
||||||
Slog.e(TAG, s);
|
Slog.e(TAG, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user