1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
20 import static android.net.ConnectivityManager.TYPE_MOBILE;
21 import static android.net.ConnectivityManager.TYPE_WIFI;
22 import static android.net.ConnectivityManager.getNetworkTypeName;
23 import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED;
24 import static org.mockito.Matchers.anyInt;
25 import static org.mockito.Matchers.eq;
26 import static org.mockito.Matchers.isA;
27 import static org.mockito.Mockito.doNothing;
28 import static org.mockito.Mockito.doReturn;
29 import static org.mockito.Mockito.doThrow;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.reset;
32 import static org.mockito.Mockito.verify;
33 
34 import android.content.Context;
35 import android.net.INetworkPolicyManager;
36 import android.net.INetworkStatsService;
37 import android.net.LinkProperties;
38 import android.net.NetworkConfig;
39 import android.net.NetworkInfo;
40 import android.net.NetworkInfo.DetailedState;
41 import android.net.NetworkStateTracker;
42 import android.net.RouteInfo;
43 import android.os.Handler;
44 import android.os.INetworkManagementService;
45 import android.test.AndroidTestCase;
46 import android.test.suitebuilder.annotation.LargeTest;
47 import android.util.Log;
48 import android.util.LogPrinter;
49 
50 import org.mockito.ArgumentCaptor;
51 
52 import java.net.InetAddress;
53 import java.util.concurrent.Future;
54 
55 /**
56  * Tests for {@link ConnectivityService}.
57  */
58 @LargeTest
59 public class ConnectivityServiceTest extends AndroidTestCase {
60     private static final String TAG = "ConnectivityServiceTest";
61 
62     private static final String MOBILE_IFACE = "rmnet3";
63     private static final String WIFI_IFACE = "wlan6";
64 
65     private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33"),
66                                                                              MOBILE_IFACE);
67     private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33"),
68                                                                              MOBILE_IFACE);
69 
70     private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute(parse("192.168.0.66"),
71                                                                            parse("192.168.0.1"),
72                                                                            WIFI_IFACE);
73     private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::66"),
74                                                                            parse("fd00::"),
75                                                                            WIFI_IFACE);
76 
77     private INetworkManagementService mNetManager;
78     private INetworkStatsService mStatsService;
79     private INetworkPolicyManager mPolicyService;
80     private ConnectivityService.NetworkFactory mNetFactory;
81 
82     private BroadcastInterceptingContext mServiceContext;
83     private ConnectivityService mService;
84 
85     private MockNetwork mMobile;
86     private MockNetwork mWifi;
87 
88     private Handler mTrackerHandler;
89 
90     private static class MockNetwork {
91         public NetworkStateTracker tracker;
92         public NetworkInfo info;
93         public LinkProperties link;
94 
MockNetwork(int type)95         public MockNetwork(int type) {
96             tracker = mock(NetworkStateTracker.class);
97             info = new NetworkInfo(type, -1, getNetworkTypeName(type), null);
98             link = new LinkProperties();
99         }
100 
doReturnDefaults()101         public void doReturnDefaults() {
102             // TODO: eventually CS should make defensive copies
103             doReturn(new NetworkInfo(info)).when(tracker).getNetworkInfo();
104             doReturn(new LinkProperties(link)).when(tracker).getLinkProperties();
105 
106             // fallback to default TCP buffers
107             doReturn("").when(tracker).getTcpBufferSizesPropName();
108         }
109     }
110 
111     @Override
setUp()112     public void setUp() throws Exception {
113         super.setUp();
114 
115         mServiceContext = new BroadcastInterceptingContext(getContext());
116 
117         mNetManager = mock(INetworkManagementService.class);
118         mStatsService = mock(INetworkStatsService.class);
119         mPolicyService = mock(INetworkPolicyManager.class);
120         mNetFactory = mock(ConnectivityService.NetworkFactory.class);
121 
122         mMobile = new MockNetwork(TYPE_MOBILE);
123         mWifi = new MockNetwork(TYPE_WIFI);
124 
125         // omit most network trackers
126         doThrow(new IllegalArgumentException("Not supported in test environment"))
127                 .when(mNetFactory).createTracker(anyInt(), isA(NetworkConfig.class));
128 
129         doReturn(mMobile.tracker)
130                 .when(mNetFactory).createTracker(eq(TYPE_MOBILE), isA(NetworkConfig.class));
131         doReturn(mWifi.tracker)
132                 .when(mNetFactory).createTracker(eq(TYPE_WIFI), isA(NetworkConfig.class));
133 
134         final ArgumentCaptor<Handler> trackerHandler = ArgumentCaptor.forClass(Handler.class);
135         doNothing().when(mMobile.tracker)
136                 .startMonitoring(isA(Context.class), trackerHandler.capture());
137 
138         mService = new ConnectivityService(
139                 mServiceContext, mNetManager, mStatsService, mPolicyService, mNetFactory);
140         mService.systemReady();
141 
142         mTrackerHandler = trackerHandler.getValue();
143         mTrackerHandler.getLooper().setMessageLogging(new LogPrinter(Log.INFO, TAG));
144     }
145 
146     @Override
tearDown()147     public void tearDown() throws Exception {
148         super.tearDown();
149     }
150 
testMobileConnectedAddedRoutes()151     public void testMobileConnectedAddedRoutes() throws Exception {
152         Future<?> nextConnBroadcast;
153 
154         // bring up mobile network
155         mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
156         mMobile.link.setInterfaceName(MOBILE_IFACE);
157         mMobile.link.addRoute(MOBILE_ROUTE_V4);
158         mMobile.link.addRoute(MOBILE_ROUTE_V6);
159         mMobile.doReturnDefaults();
160 
161         nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
162         mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
163         nextConnBroadcast.get();
164 
165         // verify that both routes were added and DNS was flushed
166         int mobileNetId = mMobile.tracker.getNetwork().netId;
167         verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
168         verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
169         verify(mNetManager).flushNetworkDnsCache(mobileNetId);
170 
171     }
172 
testMobileWifiHandoff()173     public void testMobileWifiHandoff() throws Exception {
174         Future<?> nextConnBroadcast;
175 
176         // bring up mobile network
177         mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
178         mMobile.link.setInterfaceName(MOBILE_IFACE);
179         mMobile.link.addRoute(MOBILE_ROUTE_V4);
180         mMobile.link.addRoute(MOBILE_ROUTE_V6);
181         mMobile.doReturnDefaults();
182 
183         nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
184         mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
185         nextConnBroadcast.get();
186 
187         reset(mNetManager);
188 
189         // now bring up wifi network
190         mWifi.info.setDetailedState(DetailedState.CONNECTED, null, null);
191         mWifi.link.setInterfaceName(WIFI_IFACE);
192         mWifi.link.addRoute(WIFI_ROUTE_V4);
193         mWifi.link.addRoute(WIFI_ROUTE_V6);
194         mWifi.doReturnDefaults();
195 
196         // expect that mobile will be torn down
197         doReturn(true).when(mMobile.tracker).teardown();
198 
199         nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
200         mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mWifi.info).sendToTarget();
201         nextConnBroadcast.get();
202 
203         // verify that wifi routes added, and teardown requested
204         int wifiNetId = mWifi.tracker.getNetwork().netId;
205         verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V4));
206         verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V6));
207         verify(mNetManager).flushNetworkDnsCache(wifiNetId);
208         verify(mMobile.tracker).teardown();
209 
210         int mobileNetId = mMobile.tracker.getNetwork().netId;
211 
212         reset(mNetManager, mMobile.tracker);
213 
214         // tear down mobile network, as requested
215         mMobile.info.setDetailedState(DetailedState.DISCONNECTED, null, null);
216         mMobile.link.clear();
217         mMobile.doReturnDefaults();
218 
219         nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
220         mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
221         nextConnBroadcast.get();
222 
223         verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
224         verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
225 
226     }
227 
parse(String addr)228     private static InetAddress parse(String addr) {
229         return InetAddress.parseNumericAddress(addr);
230     }
231 }
232