Loading services/java/com/android/server/ConnectivityService.java +102 −70 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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"); Loading @@ -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(), Loading Loading @@ -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) && Loading @@ -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); } Loading @@ -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; Loading @@ -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 { Loading @@ -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); Loading Loading @@ -1876,6 +1908,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 Loading Loading @@ -1934,10 +1967,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 } Loading Loading @@ -2927,11 +2959,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); } Loading services/tests/servicestests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -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 Loading services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java 0 → 100644 +224 −0 Original line number Diff line number Diff line /* * 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); } } Loading
services/java/com/android/server/ConnectivityService.java +102 −70 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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"); Loading @@ -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(), Loading Loading @@ -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) && Loading @@ -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); } Loading @@ -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; Loading @@ -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 { Loading @@ -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); Loading Loading @@ -1876,6 +1908,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 Loading Loading @@ -1934,10 +1967,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 } Loading Loading @@ -2927,11 +2959,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); } Loading
services/tests/servicestests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java 0 → 100644 +224 −0 Original line number Diff line number Diff line /* * 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); } }