ConnectivityManagerTestBase.java revision 86e15557c52e2847d2adc8495a281dcf0239506e
1/*
2 * Copyright (C) 2010, 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
17package com.android.connectivitymanagertest;
18
19import android.app.KeyguardManager;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.net.ConnectivityManager;
25import android.net.NetworkInfo;
26import android.net.NetworkInfo.State;
27import android.net.wifi.ScanResult;
28import android.net.wifi.WifiConfiguration;
29import android.net.wifi.WifiManager;
30import android.os.PowerManager;
31import android.os.SystemClock;
32import android.test.InstrumentationTestCase;
33import android.util.Log;
34import android.view.KeyEvent;
35
36import java.io.IOException;
37import java.net.UnknownHostException;
38import java.util.List;
39
40
41/**
42 * Base InstrumentationTestCase for Connectivity Manager (CM) test suite
43 *
44 * It registers connectivity manager broadcast and WiFi broadcast to provide
45 * network connectivity information, also provides a set of utility functions
46 * to modify and verify connectivity states.
47 *
48 * A CM test case should extend this base class.
49 */
50public class ConnectivityManagerTestBase extends InstrumentationTestCase {
51
52    private static final String PING_IP_ADDR = "8.8.8.8";
53
54    protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
55    protected static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
56    protected static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds
57    protected static final long LONG_TIMEOUT = 2 * 60 * 1000;  // 2 minutes
58    protected static final long WIFI_CONNECTION_TIMEOUT = 5 * 60 * 1000; // 5 minutes
59    // 2 minutes timer between wifi stop and start
60    protected static final long  WIFI_STOP_START_INTERVAL = 2 * 60 * 1000; // 2 minutes
61    // Set ping test timer to be 3 minutes
62    protected static final long PING_TIMER = 3 * 60 *1000; // 3 minutes
63    protected static final int SUCCESS = 0;  // for Wifi tethering state change
64    protected static final int FAILURE = 1;
65    protected static final int INIT = -1;
66
67    protected final String mLogTag;
68
69    private ConnectivityReceiver mConnectivityReceiver = null;
70    private WifiReceiver mWifiReceiver = null;
71
72    private long mLastConnectivityChangeTime = -1;
73    protected ConnectivityManager mCm;
74    private Context mContext;
75    protected List<ScanResult> mLastScanResult;
76    protected Object mWifiScanResultLock = new Object();
77
78    /* Control Wifi States */
79    public WifiManager mWifiManager;
80
81    public ConnectivityManagerTestBase(String logTag) {
82        super();
83        mLogTag = logTag;
84    }
85
86    protected long getLastConnectivityChangeTime() {
87        return mLastConnectivityChangeTime;
88    }
89
90    /**
91     * A wrapper of a broadcast receiver which provides network connectivity information
92     * for all kinds of network: wifi, mobile, etc.
93     */
94    private class ConnectivityReceiver extends BroadcastReceiver {
95        @Override
96        public void onReceive(Context context, Intent intent) {
97            mLastConnectivityChangeTime = SystemClock.uptimeMillis();
98            logv("ConnectivityReceiver: " + intent);
99            String action = intent.getAction();
100            if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
101                Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
102            }
103        }
104    }
105
106    private class WifiReceiver extends BroadcastReceiver {
107        @Override
108        public void onReceive(Context context, Intent intent) {
109            String action = intent.getAction();
110            Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
111            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
112                logv("scan results are available");
113                synchronized (mWifiScanResultLock) {
114                    mLastScanResult = mWifiManager.getScanResults();
115                    mWifiScanResultLock.notifyAll();
116                }
117            }
118        }
119    }
120
121    @Override
122    protected void setUp() throws Exception {
123        mLastScanResult = null;
124        mContext = getInstrumentation().getContext();
125
126        // Get an instance of ConnectivityManager
127        mCm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
128        // Get an instance of WifiManager
129        mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
130
131        if (mWifiManager.isWifiApEnabled()) {
132            // if soft AP is enabled, disable it
133            mWifiManager.setWifiApEnabled(null, false);
134            logv("Disable soft ap");
135        }
136
137        // register a connectivity receiver for CONNECTIVITY_ACTION;
138        mConnectivityReceiver = new ConnectivityReceiver();
139        mContext.registerReceiver(mConnectivityReceiver,
140                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
141
142        mWifiReceiver = new WifiReceiver();
143        IntentFilter mIntentFilter = new IntentFilter();
144        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
145        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
146        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
147        mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
148        mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
149        mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
150        mContext.registerReceiver(mWifiReceiver, mIntentFilter);
151
152        logv("Clear Wifi before we start the test.");
153        removeConfiguredNetworksAndDisableWifi();
154     }
155
156    // wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING,
157    //                                      DISCONNECTED, UNKNOWN
158    protected boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
159        long startTime = SystemClock.uptimeMillis();
160        while (true) {
161            NetworkInfo ni = mCm.getNetworkInfo(networkType);
162            if (ni != null && expectedState.equals(ni.getState())) {
163                logv("waitForNetworkState success: %s", ni);
164                return true;
165            }
166            if ((SystemClock.uptimeMillis() - startTime) > timeout) {
167                logv("waitForNetworkState timeout: %s", ni);
168                return false;
169            }
170            logv("waitForNetworkState interim: %s", ni);
171            SystemClock.sleep(SHORT_TIMEOUT);
172        }
173    }
174
175    // wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
176    //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
177    protected boolean waitForWifiState(int expectedState, long timeout) {
178        long startTime = SystemClock.uptimeMillis();
179        while (true) {
180            int state = mWifiManager.getWifiState();
181            if (state == expectedState) {
182                logv("waitForWifiState success: state=" + state);
183                return true;
184            }
185            if ((SystemClock.uptimeMillis() - startTime) > timeout) {
186                logv("waitForWifiState timeout: expected=%d, actual=%d", expectedState, state);
187                return false;
188            }
189            logv("waitForWifiState interim: expected=%d, actual=%d", expectedState, state);
190            SystemClock.sleep(SHORT_TIMEOUT);
191        }
192    }
193
194    // Wait for Wifi AP state: WIFI_AP_STATE_DISABLED, WIFI_AP_STATE_DISABLING,
195    //                         WIFI_AP_STATE_ENABLED, WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
196    protected boolean waitForWifiApState(int expectedState, long timeout) {
197        long startTime = SystemClock.uptimeMillis();
198        while (true) {
199            int state = mWifiManager.getWifiApState();
200            if (state == expectedState) {
201                logv("waitForWifiAPState success: state=" + state);
202                return true;
203            }
204            if ((SystemClock.uptimeMillis() - startTime) > timeout) {
205                logv(String.format("waitForWifiAPState timeout: expected=%d, actual=%d",
206                        expectedState, state));
207                return false;
208            }
209            logv(String.format("waitForWifiAPState interim: expected=%d, actual=%d",
210                    expectedState, state));
211            SystemClock.sleep(SHORT_TIMEOUT);
212        }
213    }
214
215    /**
216     * Wait for the wifi tethering result:
217     * @param timeout is the maximum waiting time
218     * @return SUCCESS if tethering result is successful
219     *         FAILURE if tethering result returns error.
220     */
221    protected boolean waitForTetherStateChange(long timeout) {
222        long startTime = SystemClock.uptimeMillis();
223        String[] wifiRegexes = mCm.getTetherableWifiRegexs();
224        while (true) {
225            if ((SystemClock.uptimeMillis() - startTime) > timeout) {
226                return false;
227            }
228            String[] active = mCm.getTetheredIfaces();
229            String[] error = mCm.getTetheringErroredIfaces();
230            for (String iface: active) {
231                for (String regex: wifiRegexes) {
232                    if (iface.matches(regex)) {
233                        return true;
234                    }
235                }
236            }
237            for (String iface: error) {
238                for (String regex: wifiRegexes) {
239                    if (iface.matches(regex)) {
240                        return false;
241                    }
242                }
243            }
244            SystemClock.sleep(SHORT_TIMEOUT);
245        }
246    }
247
248    // Return true if device is currently connected to mobile network
249    protected boolean isConnectedToMobile() {
250        return (mCm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_MOBILE);
251    }
252
253    // Return true if device is currently connected to Wifi
254    protected boolean isConnectedToWifi() {
255        return (mCm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI);
256    }
257
258    protected boolean enableWifi() {
259        return mWifiManager.setWifiEnabled(true);
260    }
261
262    // Turn screen off
263    protected void turnScreenOff() {
264        logv("Turn screen off");
265        PowerManager pm =
266            (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
267        pm.goToSleep(SystemClock.uptimeMillis());
268    }
269
270    // Turn screen on
271    protected void turnScreenOn() {
272        logv("Turn screen on");
273        PowerManager pm =
274                (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
275        pm.wakeUp(SystemClock.uptimeMillis());
276        // disable lock screen
277        KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
278        if (km.inKeyguardRestrictedInputMode()) {
279            sendKeys(KeyEvent.KEYCODE_MENU);
280        }
281    }
282
283    /**
284     * @param pingServerList a list of servers that can be used for ping test, can be null
285     * @return true if the ping test is successful, false otherwise.
286     */
287    protected boolean pingTest(String[] pingServerList) {
288        String[] hostList = {"www.google.com", "www.yahoo.com",
289                "www.bing.com", "www.facebook.com", "www.ask.com"};
290        if (pingServerList != null) {
291            hostList = pingServerList;
292        }
293
294        long startTime = System.currentTimeMillis();
295        while ((System.currentTimeMillis() - startTime) < PING_TIMER) {
296            try {
297                // assume the chance that all servers are down is very small
298                for (int i = 0; i < hostList.length; i++ ) {
299                    String host = hostList[i];
300                    logv("Start ping test, ping " + host);
301                    Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
302                    int status = p.waitFor();
303                    if (status == 0) {
304                        // if any of the ping test is successful, return true
305                        return true;
306                    }
307                }
308            } catch (UnknownHostException e) {
309                logv("Ping test Fail: Unknown Host");
310            } catch (IOException e) {
311                logv("Ping test Fail:  IOException");
312            } catch (InterruptedException e) {
313                logv("Ping test Fail: InterruptedException");
314            }
315        }
316        // ping test timeout
317        return false;
318    }
319
320    /**
321     * Associate the device to given SSID
322     * If the device is already associated with a WiFi, disconnect and forget it,
323     * We don't verify whether the connection is successful or not, leave this to the test
324     */
325    protected boolean connectToWifi(String ssid, String password) {
326        WifiConfiguration config;
327        if (password == null) {
328            config = WifiConfigurationHelper.createOpenConfig(ssid);
329        } else {
330            config = WifiConfigurationHelper.createPskConfig(ssid, password);
331        }
332        return connectToWifiWithConfiguration(config);
333    }
334
335    /**
336     * Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
337     * is pure string, we need to convert it to quoted string.
338     */
339    protected boolean connectToWifiWithConfiguration(WifiConfiguration config) {
340        // If Wifi is not enabled, enable it
341        if (!mWifiManager.isWifiEnabled()) {
342            logv("Wifi is not enabled, enable it");
343            mWifiManager.setWifiEnabled(true);
344            // wait for the wifi state change before start scanning.
345            if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT)) {
346                logv("wait for WIFI_STATE_ENABLED failed");
347                return false;
348            }
349        }
350
351        // Save network configuration and connect to network without scanning
352        mWifiManager.connect(config,
353            new WifiManager.ActionListener() {
354                @Override
355                public void onSuccess() {
356                }
357
358                @Override
359                public void onFailure(int reason) {
360                    logv("connect failure " + reason);
361                }
362            });
363        return true;
364    }
365
366    /*
367     * Disconnect from the current AP and remove configured networks.
368     */
369    protected boolean disconnectAP() {
370        // remove saved networks
371        if (!mWifiManager.isWifiEnabled()) {
372            logv("Enabled wifi before remove configured networks");
373            mWifiManager.setWifiEnabled(true);
374            SystemClock.sleep(SHORT_TIMEOUT);
375        }
376
377        List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
378        if (wifiConfigList == null) {
379            logv("no configuration list is null");
380            return true;
381        }
382        logv("size of wifiConfigList: " + wifiConfigList.size());
383        for (WifiConfiguration wifiConfig: wifiConfigList) {
384            logv("remove wifi configuration: " + wifiConfig.networkId);
385            int netId = wifiConfig.networkId;
386            mWifiManager.forget(netId, new WifiManager.ActionListener() {
387                    @Override
388                    public void onSuccess() {
389                    }
390
391                    @Override
392                    public void onFailure(int reason) {
393                        logv("Failed to forget " + reason);
394                    }
395                });
396        }
397        return true;
398    }
399    /**
400     * Disable Wifi
401     * @return true if Wifi is disabled successfully
402     */
403    protected boolean disableWifi() {
404        return mWifiManager.setWifiEnabled(false);
405    }
406
407    /**
408     * Remove configured networks and disable wifi
409     */
410    protected boolean removeConfiguredNetworksAndDisableWifi() {
411        if (!disconnectAP()) {
412           return false;
413        }
414        SystemClock.sleep(SHORT_TIMEOUT);
415        if (!mWifiManager.setWifiEnabled(false)) {
416            return false;
417        }
418        SystemClock.sleep(SHORT_TIMEOUT);
419        return true;
420    }
421
422    protected static String convertToQuotedString(String string) {
423        return "\"" + string + "\"";
424    }
425
426    protected boolean waitForActiveNetworkConnection(long timeout) {
427        long startTime = SystemClock.uptimeMillis();
428        while (true) {
429            NetworkInfo ni = mCm.getActiveNetworkInfo();
430            if (ni != null && ni.isConnected()) {
431                return true;
432            }
433            if ((SystemClock.uptimeMillis() - startTime) > timeout) {
434                logv("waitForActiveNetworkConnection timeout: %s", ni);
435                return false;
436            }
437            logv("waitForActiveNetworkConnection interim: %s", ni);
438            SystemClock.sleep(SHORT_TIMEOUT);
439        }
440    }
441
442    protected boolean waitUntilNoActiveNetworkConnection(long timeout) {
443        long startTime = SystemClock.uptimeMillis();
444        while (true) {
445            NetworkInfo ni = mCm.getActiveNetworkInfo();
446            if (ni == null) {
447                return true;
448            }
449            if ((SystemClock.uptimeMillis() - startTime) > timeout) {
450                logv("waitForActiveNetworkConnection timeout: %s", ni);
451                return false;
452            }
453            logv("waitForActiveNetworkConnection interim: %s", ni);
454            SystemClock.sleep(SHORT_TIMEOUT);
455        }
456    }
457
458    // use ping request against Google public DNS to verify connectivity
459    protected boolean checkNetworkConnectivity() {
460        assertTrue("no active network connection", waitForActiveNetworkConnection(LONG_TIMEOUT));
461        try {
462            Process proc = Runtime.getRuntime().exec(new String[]{
463                    "/system/bin/ping", "-W", "30", "-c", "1", PING_IP_ADDR});
464            return proc.waitFor() == 0;
465        } catch (InterruptedException | IOException e) {
466            Log.e(mLogTag, "Ping failed", e);
467        }
468        return false;
469    }
470
471    @Override
472    protected void tearDown() throws Exception{
473        //Unregister receiver
474        if (mConnectivityReceiver != null) {
475          mContext.unregisterReceiver(mConnectivityReceiver);
476        }
477        if (mWifiReceiver != null) {
478          mContext.unregisterReceiver(mWifiReceiver);
479        }
480        super.tearDown();
481    }
482
483    protected void logv(String format, Object... args) {
484        Log.v(mLogTag, String.format(format, args));
485    }
486
487    /**
488     * Connect to the provided Wi-Fi network
489     * @param config is the network configuration
490     * @throws AssertionError if fails to associate and connect to wifi ap
491     */
492    protected void connectToWifi(WifiConfiguration config) {
493        // step 1: connect to the test access point
494        assertTrue("failed to associate with " + config.SSID,
495                connectToWifiWithConfiguration(config));
496
497        // step 2: verify Wifi state and network state;
498        assertTrue("wifi state not connected with " + config.SSID,
499                waitForNetworkState(ConnectivityManager.TYPE_WIFI,
500                State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
501
502        // step 3: verify the current connected network is the given SSID
503        assertNotNull("no active wifi info", mWifiManager.getConnectionInfo());
504        assertEquals("SSID mismatch", config.SSID, mWifiManager.getConnectionInfo().getSSID());
505    }
506}
507