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.stress;
18
19import android.content.Context;
20import android.net.ConnectivityManager;
21import android.net.NetworkInfo.State;
22import android.net.wifi.ScanResult;
23import android.net.wifi.WifiConfiguration;
24import android.net.wifi.WifiConfiguration.IpAssignment;
25import android.net.wifi.WifiConfiguration.KeyMgmt;
26import android.net.wifi.WifiConfiguration.ProxySettings;
27import android.net.wifi.WifiManager;
28import android.os.Environment;
29import android.os.PowerManager;
30import android.provider.Settings;
31import android.view.KeyEvent;
32import android.test.suitebuilder.annotation.LargeTest;
33import android.util.Log;
34
35import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
36import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
37
38import java.io.BufferedWriter;
39import java.io.File;
40import java.io.FileWriter;
41import java.io.IOException;
42import java.util.List;
43
44/**
45 * Stress Wi-Fi connection, scanning and reconnection after sleep.
46 *
47 * To run this stress test suite, type
48 * adb shell am instrument -e class com.android.connectivitymanagertest.stress.WifiStressTest
49 *                  -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
50 */
51public class WifiStressTest
52        extends ConnectivityManagerTestBase {
53    private final static String TAG = "WifiStressTest";
54
55    /**
56     * Wi-Fi idle time for default sleep policy
57     */
58    private final static long WIFI_IDLE_MS = 60 * 1000;
59
60    /**
61     * Delay after issuing wifi shutdown.
62     * The framework keep driver up for at leat 2 minutes to avoid problems
63     * that a quick shutdown could cause on wext driver and protentially
64     * on cfg based driver
65     */
66    private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000;
67
68    private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
69    private int mReconnectIterations;
70    private int mWifiSleepTime;
71    private int mScanIterations;
72    private String mSsid;
73    private String mPassword;
74    private ConnectivityManagerStressTestRunner mRunner;
75    private BufferedWriter mOutputWriter = null;
76    private boolean mWifiOnlyFlag;
77
78    @Override
79    public void setUp() throws Exception {
80        super.setUp();
81
82        mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation();
83        mReconnectIterations = mRunner.mReconnectIterations;
84        mSsid = mRunner.mReconnectSsid;
85        mPassword = mRunner.mReconnectPassword;
86        mScanIterations = mRunner.mScanIterations;
87        mWifiSleepTime = mRunner.mSleepTime;
88        mWifiOnlyFlag = mRunner.mWifiOnlyFlag;
89        log(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s),"
90            + "mScanIterations(%d), mWifiSleepTime(%d)", mReconnectIterations, mSsid,
91            mPassword, mScanIterations, mWifiSleepTime));
92        mOutputWriter = new BufferedWriter(new FileWriter(new File(
93                Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
94        turnScreenOn();
95        if (!mWifiManager.isWifiEnabled()) {
96            log("Enable wi-fi before stress tests.");
97            if (!enableWifi()) {
98                tearDown();
99                fail("enable wifi failed.");
100            }
101            sleep(SHORT_TIMEOUT, "Interruped while waiting for wifi on");
102        }
103    }
104
105    @Override
106    public void tearDown() throws Exception {
107        log("tearDown()");
108        if (mOutputWriter != null) {
109            mOutputWriter.close();
110        }
111        super.tearDown();
112    }
113
114    private void writeOutput(String s) {
115        log("write message: " + s);
116        if (mOutputWriter == null) {
117            log("no writer attached to file " + OUTPUT_FILE);
118            return;
119        }
120        try {
121            mOutputWriter.write(s + "\n");
122            mOutputWriter.flush();
123        } catch (IOException e) {
124            log("failed to write output.");
125        }
126    }
127
128    public void log(String message) {
129        Log.v(TAG, message);
130    }
131
132    private void sleep(long sometime, String errorMsg) {
133        try {
134            Thread.sleep(sometime);
135        } catch (InterruptedException e) {
136            fail(errorMsg);
137        }
138    }
139
140    /**
141     *  Stress Wifi Scanning
142     *  TODO: test the scanning quality for each frequency band
143     */
144    @LargeTest
145    public void testWifiScanning() {
146        int scanTimeSum = 0;
147        int i;
148        int ssidAppearInScanResultsCount = 0; // count times of given ssid appear in scan results.
149        for (i = 0; i < mScanIterations; i++) {
150            log("testWifiScanning: iteration: " + i);
151            int averageScanTime = 0;
152            if (i > 0) {
153                averageScanTime = scanTimeSum/i;
154            }
155            writeOutput(String.format("iteration %d out of %d",
156                    i, mScanIterations));
157            writeOutput(String.format("average scanning time is %d", averageScanTime));
158            writeOutput(String.format("ssid appear %d out of %d scan iterations",
159                    ssidAppearInScanResultsCount, i));
160            long startTime = System.currentTimeMillis();
161            scanResultAvailable = false;
162            assertTrue("start scan failed", mWifiManager.startScan());
163            while (true) {
164                if ((System.currentTimeMillis() - startTime) >
165                WIFI_SCAN_TIMEOUT) {
166                    fail("Wifi scanning takes more than " + WIFI_SCAN_TIMEOUT + " ms");
167                }
168                synchronized(this) {
169                    try {
170                        wait(WAIT_FOR_SCAN_RESULT);
171                    } catch (InterruptedException e) {
172                        e.printStackTrace();
173                    }
174                    if (scanResultAvailable) {
175                        long scanTime = (System.currentTimeMillis() - startTime);
176                        scanTimeSum += scanTime;
177                        break;
178                    }
179                }
180            }
181            if ((mWifiManager.getScanResults() == null) ||
182                    (mWifiManager.getScanResults().size() <= 0)) {
183                fail("Scan results are empty ");
184            }
185
186            List<ScanResult> netList = mWifiManager.getScanResults();
187            if (netList != null) {
188                log("size of scan result list: " + netList.size());
189                for (int s = 0; s < netList.size(); s++) {
190                    ScanResult sr= netList.get(s);
191                    log(String.format("scan result for %s is: %s", sr.SSID, sr.toString()));
192                    log(String.format("signal level for %s is %d ", sr.SSID, sr.level));
193                    if (sr.SSID.equals(mSsid)) {
194                        ssidAppearInScanResultsCount += 1;
195                        log("Number of times " + mSsid + " appear in the scan list: " +
196                                ssidAppearInScanResultsCount);
197                        break;
198                    }
199                }
200            }
201        }
202        if (i == mScanIterations) {
203            writeOutput(String.format("iteration %d out of %d",
204                    i, mScanIterations));
205            writeOutput(String.format("average scanning time is %d", scanTimeSum/mScanIterations));
206            writeOutput(String.format("ssid appear %d out of %d scan iterations",
207                    ssidAppearInScanResultsCount, mScanIterations));
208        }
209    }
210
211    // Stress Wifi reconnection to secure net after sleep
212    @LargeTest
213    public void testWifiReconnectionAfterSleep() {
214        int value = Settings.Global.getInt(mRunner.getContext().getContentResolver(),
215                Settings.Global.WIFI_SLEEP_POLICY, -1);
216        log("wifi sleep policy is: " + value);
217        if (value != Settings.Global.WIFI_SLEEP_POLICY_DEFAULT) {
218            Settings.Global.putInt(mRunner.getContext().getContentResolver(),
219                    Settings.Global.WIFI_SLEEP_POLICY, Settings.Global.WIFI_SLEEP_POLICY_DEFAULT);
220            log("set wifi sleep policy to default value");
221        }
222        Settings.Global.putLong(mRunner.getContext().getContentResolver(),
223                Settings.Global.WIFI_IDLE_MS, WIFI_IDLE_MS);
224
225        // Connect to a Wi-Fi network
226        WifiConfiguration config = new WifiConfiguration();
227        config.SSID = mSsid;
228        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
229        if (mPassword.matches("[0-9A-Fa-f]{64}")) {
230            config.preSharedKey = mPassword;
231        } else {
232            config.preSharedKey = '"' + mPassword + '"';
233        }
234        config.ipAssignment = IpAssignment.DHCP;
235        config.proxySettings = ProxySettings.NONE;
236
237        assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
238                connectToWifiWithConfiguration(config));
239        assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
240                SHORT_TIMEOUT));
241        assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
242                WIFI_CONNECTION_TIMEOUT));
243        // Run ping test to verify the data connection
244        assertTrue("Wi-Fi is connected, but no data connection.", pingTest(null));
245
246        int i;
247        long sum = 0;
248        for (i = 0; i < mReconnectIterations; i++) {
249            // 1. Put device into sleep mode
250            // 2. Wait for the device to sleep for sometime, verify wi-fi is off and mobile is on.
251            // 3. Maintain the sleep mode for some time,
252            // 4. Verify the Wi-Fi is still off, and data is on
253            // 5. Wake up the device, verify Wi-Fi is enabled and connected.
254            writeOutput(String.format("iteration %d out of %d",
255                    i, mReconnectIterations));
256            log("iteration: " + i);
257            turnScreenOff();
258            PowerManager pm =
259                (PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE);
260            assertFalse(pm.isScreenOn());
261            sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY, "Interruped while wait for wifi to be idle");
262            assertTrue("Wait for Wi-Fi to idle timeout",
263                    waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
264                    6 * SHORT_TIMEOUT));
265            if (!mWifiOnlyFlag) {
266                // use long timeout as the pppd startup may take several retries.
267                assertTrue("Wait for cellular connection timeout",
268                        waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
269                        2 * LONG_TIMEOUT));
270            }
271            sleep(mWifiSleepTime, "Interrupted while device is in sleep mode");
272            // Verify the wi-fi is still off and data connection is on
273            assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
274                    mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
275
276            if (!mWifiOnlyFlag) {
277                assertEquals("Cellular connection is down", State.CONNECTED,
278                             mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
279                assertTrue("Mobile is connected, but no data connection.", pingTest(null));
280            }
281
282            // Turn screen on again
283            turnScreenOn();
284            // Wait for 2 seconds for the lock screen
285            sleep(2 * 1000, "wait 2 seconds for lock screen");
286            // Disable lock screen by inject menu key event
287            mRunner.sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
288
289            // Measure the time for Wi-Fi to get connected
290            long startTime = System.currentTimeMillis();
291            assertTrue("Wait for Wi-Fi enable timeout after wake up",
292                    waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
293                    SHORT_TIMEOUT));
294            assertTrue("Wait for Wi-Fi connection timeout after wake up",
295                    waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
296                    WIFI_CONNECTION_TIMEOUT));
297            long connectionTime = System.currentTimeMillis() - startTime;
298            sum += connectionTime;
299            log("average reconnection time is: " + sum/(i+1));
300
301            assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
302        }
303        if (i == mReconnectIterations) {
304            writeOutput(String.format("iteration %d out of %d",
305                    i, mReconnectIterations));
306        }
307    }
308}
309