BluetoothStressTest.java revision e1d666b632608a2f708cb3df06c796e16d5d1717
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 android.bluetooth;
18
19import java.io.BufferedWriter;
20import java.io.File;
21import java.io.FileWriter;
22import java.io.IOException;
23
24import android.app.Instrumentation;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.os.Environment;
30import android.test.InstrumentationTestCase;
31import android.util.Log;
32
33public class BluetoothStressTest extends InstrumentationTestCase {
34    private static final String TAG = "BluetoothStressTest";
35    private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
36
37    /**
38     * Timeout for {@link BluetoothAdapter#disable()} in ms.
39     */
40    private static final int DISABLE_TIMEOUT = 5000;
41
42    /**
43     * Timeout for {@link BluetoothAdapter#enable()} in ms.
44     */
45    private static final int ENABLE_TIMEOUT = 20000;
46
47    /**
48     * Timeout for {@link BluetoothAdapter#setScanMode(int)} in ms.
49     */
50    private static final int SET_SCAN_MODE_TIMEOUT = 5000;
51
52    /**
53     * Timeout for {@link BluetoothAdapter#startDiscovery()} in ms.
54     */
55    private static final int START_DISCOVERY_TIMEOUT = 5000;
56
57    /**
58     * Timeout for {@link BluetoothAdapter#cancelDiscovery()} in ms.
59     */
60    private static final int CANCEL_DISCOVERY_TIMEOUT = 5000;
61
62    private static final int DISCOVERY_STARTED_FLAG = 1;
63    private static final int DISCOVERY_FINISHED_FLAG = 1 << 1;
64    private static final int SCAN_MODE_NONE_FLAG = 1 << 2;
65    private static final int SCAN_MODE_CONNECTABLE_FLAG = 1 << 3;
66    private static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG = 1 << 4;
67    private static final int STATE_OFF_FLAG = 1 << 5;
68    private static final int STATE_TURNING_ON_FLAG = 1 << 6;
69    private static final int STATE_ON_FLAG = 1 << 7;
70    private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
71
72    /**
73     * Time between polls in ms.
74     */
75    private static final int POLL_TIME = 100;
76
77    private Context mContext;
78
79    private Instrumentation mInstrumentation;
80
81    private BufferedWriter mOutputWriter;
82
83    private class BluetoothReceiver extends BroadcastReceiver {
84        private int mFiredFlags = 0;
85
86        @Override
87        public void onReceive(Context context, Intent intent) {
88            synchronized (this) {
89                if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
90                    mFiredFlags |= DISCOVERY_STARTED_FLAG;
91                } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
92                    mFiredFlags |= DISCOVERY_FINISHED_FLAG;
93                } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
94                    int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
95                            BluetoothAdapter.ERROR);
96                    assertNotSame(mode, BluetoothAdapter.ERROR);
97                    switch (mode) {
98                        case BluetoothAdapter.SCAN_MODE_NONE:
99                            mFiredFlags |= SCAN_MODE_NONE_FLAG;
100                            break;
101                        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
102                            mFiredFlags |= SCAN_MODE_CONNECTABLE_FLAG;
103                            break;
104                        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
105                            mFiredFlags |= SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
106                            break;
107                    }
108                } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
109                    int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
110                            BluetoothAdapter.ERROR);
111                    assertNotSame(state, BluetoothAdapter.ERROR);
112                    switch (state) {
113                        case BluetoothAdapter.STATE_OFF:
114                            mFiredFlags |= STATE_OFF_FLAG;
115                            break;
116                        case BluetoothAdapter.STATE_TURNING_ON:
117                            mFiredFlags |= STATE_TURNING_ON_FLAG;
118                            break;
119                        case BluetoothAdapter.STATE_ON:
120                            mFiredFlags |= STATE_ON_FLAG;
121                            break;
122                        case BluetoothAdapter.STATE_TURNING_OFF:
123                            mFiredFlags |= STATE_TURNING_OFF_FLAG;
124                            break;
125                    }
126                }
127            }
128        }
129
130        public int getFiredFlags() {
131            synchronized (this) {
132                return mFiredFlags;
133            }
134        }
135
136        public void resetFiredFlags() {
137            synchronized (this) {
138                mFiredFlags = 0;
139            }
140        }
141    }
142
143    private BluetoothReceiver mReceiver = new BluetoothReceiver();
144
145    @Override
146    protected void setUp() throws Exception {
147        super.setUp();
148
149        mInstrumentation = getInstrumentation();
150        mContext = mInstrumentation.getTargetContext();
151
152        try {
153            mOutputWriter = new BufferedWriter(new FileWriter(new File(
154                    Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
155        } catch (IOException e) {
156            Log.w(TAG, "Test output file could not be opened", e);
157            mOutputWriter = null;
158        }
159
160        IntentFilter filter = new IntentFilter();
161        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
162        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
163        filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
164        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
165        mContext.registerReceiver(mReceiver, filter);
166    }
167
168    @Override
169    protected void tearDown() throws Exception {
170        super.tearDown();
171
172        mContext.unregisterReceiver(mReceiver);
173
174        if (mOutputWriter != null) {
175            try {
176                mOutputWriter.close();
177            } catch (IOException e) {
178                Log.w(TAG, "Test output file could not be closed", e);
179            }
180        }
181    }
182
183    public void testEnable() {
184        int iterations = BluetoothTestRunner.sEnableIterations;
185        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
186
187        for (int i = 0; i < iterations; i++) {
188            writeOutput("enable iteration " + (i + 1) + " of " + iterations);
189            enable(adapter);
190            disable(adapter);
191        }
192    }
193
194    public void testDiscoverable() {
195        int iterations = BluetoothTestRunner.sDiscoverableIterations;
196        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
197        enable(adapter);
198
199        for (int i = 0; i < iterations; i++) {
200            writeOutput("discoverable iteration " + (i + 1) + " of " + iterations);
201            discoverable(adapter);
202            undiscoverable(adapter);
203        }
204
205        disable(adapter);
206    }
207
208    public void testScan() {
209        int iterations = BluetoothTestRunner.sScanIterations;
210        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
211        enable(adapter);
212
213        for (int i = 0; i < iterations; i++) {
214            writeOutput("scan iteration " + (i + 1) + " of " + iterations);
215            startScan(adapter);
216            stopScan(adapter);
217        }
218
219        disable(adapter);
220    }
221
222    private void disable(BluetoothAdapter adapter) {
223        int mask = STATE_TURNING_OFF_FLAG | STATE_OFF_FLAG | SCAN_MODE_NONE_FLAG;
224        mReceiver.resetFiredFlags();
225
226        int state = adapter.getState();
227        switch (state) {
228            case BluetoothAdapter.STATE_OFF:
229                assertFalse(adapter.isEnabled());
230                return;
231            case BluetoothAdapter.STATE_ON:
232                assertTrue(adapter.isEnabled());
233                assertTrue(adapter.disable());
234                break;
235            case BluetoothAdapter.STATE_TURNING_ON:
236                assertFalse(adapter.isEnabled());
237                assertTrue(adapter.disable());
238                break;
239            case BluetoothAdapter.STATE_TURNING_OFF:
240                assertFalse(adapter.isEnabled());
241                mask = 0; // Don't check for received intents since we might have missed them.
242                break;
243            default:
244                fail("disable() invalid state: state=" + state);
245        }
246
247        long s = System.currentTimeMillis();
248        while (System.currentTimeMillis() - s < DISABLE_TIMEOUT) {
249            state = adapter.getState();
250            if (state == BluetoothAdapter.STATE_OFF) {
251                assertFalse(adapter.isEnabled());
252                if ((mReceiver.getFiredFlags() & mask) == mask) {
253                    mReceiver.resetFiredFlags();
254                    writeOutput(String.format("disable() completed in %d ms",
255                            (System.currentTimeMillis() - s)));
256                    return;
257                }
258            } else {
259                assertFalse(adapter.isEnabled());
260                assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
261            }
262            sleep(POLL_TIME);
263        }
264
265        int firedFlags = mReceiver.getFiredFlags();
266        mReceiver.resetFiredFlags();
267        fail(String.format("disable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
268                state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
269    }
270
271    private void enable(BluetoothAdapter adapter) {
272        int mask = STATE_TURNING_ON_FLAG | STATE_ON_FLAG | SCAN_MODE_CONNECTABLE_FLAG;
273        mReceiver.resetFiredFlags();
274
275        int state = adapter.getState();
276        switch (state) {
277            case BluetoothAdapter.STATE_ON:
278                assertTrue(adapter.isEnabled());
279                return;
280            case BluetoothAdapter.STATE_OFF:
281            case BluetoothAdapter.STATE_TURNING_OFF:
282                assertFalse(adapter.isEnabled());
283                assertTrue(adapter.enable());
284                break;
285            case BluetoothAdapter.STATE_TURNING_ON:
286                assertFalse(adapter.isEnabled());
287                mask = 0; // Don't check for received intents since we might have missed them.
288                break;
289            default:
290                fail("enable() invalid state: state=" + state);
291        }
292
293        long s = System.currentTimeMillis();
294        while (System.currentTimeMillis() - s < ENABLE_TIMEOUT) {
295            state = adapter.getState();
296            if (state == BluetoothAdapter.STATE_ON) {
297                assertTrue(adapter.isEnabled());
298                if ((mReceiver.getFiredFlags() & mask) == mask) {
299                    mReceiver.resetFiredFlags();
300                    writeOutput(String.format("enable() completed in %d ms",
301                            (System.currentTimeMillis() - s)));
302                    return;
303                }
304            } else {
305                assertFalse(adapter.isEnabled());
306                assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
307            }
308            sleep(POLL_TIME);
309        }
310
311        int firedFlags = mReceiver.getFiredFlags();
312        mReceiver.resetFiredFlags();
313        fail(String.format("enable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
314                state, BluetoothAdapter.STATE_ON, firedFlags, mask));
315    }
316
317    private void discoverable(BluetoothAdapter adapter) {
318        int mask = SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
319        mReceiver.resetFiredFlags();
320
321        if (!adapter.isEnabled()) {
322            fail("discoverable() bluetooth not enabled");
323        }
324
325        int scanMode = adapter.getScanMode();
326        if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
327            return;
328        }
329
330        assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE);
331        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
332
333        long s = System.currentTimeMillis();
334        while (System.currentTimeMillis() - s < SET_SCAN_MODE_TIMEOUT) {
335            scanMode = adapter.getScanMode();
336            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
337                if ((mReceiver.getFiredFlags() & mask) == mask) {
338                    mReceiver.resetFiredFlags();
339                    writeOutput(String.format("discoverable() completed in %d ms",
340                            (System.currentTimeMillis() - s)));
341                    return;
342                }
343            } else {
344                assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE);
345            }
346            sleep(POLL_TIME);
347        }
348
349        int firedFlags = mReceiver.getFiredFlags();
350        mReceiver.resetFiredFlags();
351        fail(String.format("discoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
352                + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,
353                firedFlags, mask));
354    }
355
356    private void undiscoverable(BluetoothAdapter adapter) {
357        int mask = SCAN_MODE_CONNECTABLE_FLAG;
358        mReceiver.resetFiredFlags();
359
360        if (!adapter.isEnabled()) {
361            fail("undiscoverable() bluetooth not enabled");
362        }
363
364        int scanMode = adapter.getScanMode();
365        if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
366            return;
367        }
368
369        assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
370        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
371
372        long s = System.currentTimeMillis();
373        while (System.currentTimeMillis() - s < SET_SCAN_MODE_TIMEOUT) {
374            scanMode = adapter.getScanMode();
375            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
376                if ((mReceiver.getFiredFlags() & mask) == mask) {
377                    mReceiver.resetFiredFlags();
378                    writeOutput(String.format("undiscoverable() completed in %d ms",
379                            (System.currentTimeMillis() - s)));
380                    return;
381                }
382            } else {
383                assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
384            }
385            sleep(POLL_TIME);
386        }
387
388        int firedFlags = mReceiver.getFiredFlags();
389        mReceiver.resetFiredFlags();
390        fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
391                + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE, firedFlags,
392                mask));
393    }
394
395    private void startScan(BluetoothAdapter adapter) {
396        int mask = DISCOVERY_STARTED_FLAG;
397        mReceiver.resetFiredFlags();
398
399        if (!adapter.isEnabled()) {
400            fail("startScan() bluetooth not enabled");
401        }
402
403        if (adapter.isDiscovering()) {
404            return;
405        }
406
407        assertTrue(adapter.startDiscovery());
408
409        long s = System.currentTimeMillis();
410        while (System.currentTimeMillis() - s < START_DISCOVERY_TIMEOUT) {
411            if (adapter.isDiscovering() && ((mReceiver.getFiredFlags() & mask) == mask)) {
412                mReceiver.resetFiredFlags();
413                writeOutput(String.format("startScan() completed in %d ms",
414                        (System.currentTimeMillis() - s)));
415                return;
416            }
417            sleep(POLL_TIME);
418        }
419
420        int firedFlags = mReceiver.getFiredFlags();
421        mReceiver.resetFiredFlags();
422        fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
423                adapter.isDiscovering(), firedFlags, mask));
424    }
425
426    private void stopScan(BluetoothAdapter adapter) {
427        int mask = DISCOVERY_FINISHED_FLAG;
428        mReceiver.resetFiredFlags();
429
430        if (!adapter.isEnabled()) {
431            fail("stopScan() bluetooth not enabled");
432        }
433
434        if (!adapter.isDiscovering()) {
435            return;
436        }
437
438        // TODO: put assertTrue() around cancelDiscovery() once it starts
439        // returning true.
440        adapter.cancelDiscovery();
441
442        long s = System.currentTimeMillis();
443        while (System.currentTimeMillis() - s < CANCEL_DISCOVERY_TIMEOUT) {
444            if (!adapter.isDiscovering() && ((mReceiver.getFiredFlags() & mask) == mask)) {
445                mReceiver.resetFiredFlags();
446                writeOutput(String.format("stopScan() completed in %d ms",
447                        (System.currentTimeMillis() - s)));
448                return;
449            }
450            sleep(POLL_TIME);
451        }
452
453        int firedFlags = mReceiver.getFiredFlags();
454        mReceiver.resetFiredFlags();
455        fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
456                adapter.isDiscovering(), firedFlags, mask));
457
458    }
459
460    private void writeOutput(String s) {
461        if (mOutputWriter == null) {
462            return;
463        }
464        try {
465            Log.i(TAG, s);
466            mOutputWriter.write(s + "\n");
467            mOutputWriter.flush();
468        } catch (IOException e) {
469            Log.w(TAG, "Could not write to output file", e);
470        }
471    }
472
473    private void sleep(long time) {
474        try {
475            Thread.sleep(time);
476        } catch (InterruptedException e) {
477        }
478    }
479}
480