summaryrefslogtreecommitdiffstats
path: root/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
blob: 24bcae2966f21db47de6d11d014e56fb1121e229 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
/*
 * Copyright (C) 2016 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.wifi.scanner;

import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
import static com.android.server.wifi.ScanTestUtil.assertScanDataEquals;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import android.app.test.TestAlarmManager;
import android.content.Context;
import android.net.wifi.WifiScanner;
import android.os.SystemClock;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.internal.R;
import com.android.server.wifi.Clock;
import com.android.server.wifi.MockResources;
import com.android.server.wifi.MockWifiMonitor;
import com.android.server.wifi.ScanResults;
import com.android.server.wifi.WifiMonitor;
import com.android.server.wifi.WifiNative;
import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Arrays;
import java.util.Set;

/**
 * Unit tests for {@link com.android.server.wifi.scanner.WificondScannerImpl.setPnoList}.
 */
@SmallTest
public class WificondPnoScannerTest {

    @Mock Context mContext;
    TestAlarmManager mAlarmManager;
    MockWifiMonitor mWifiMonitor;
    TestLooper mLooper;
    @Mock WifiNative mWifiNative;
    MockResources mResources;
    @Mock Clock mClock;
    WificondScannerImpl mScanner;

    @Before
    public void setup() throws Exception {
        MockitoAnnotations.initMocks(this);

        mLooper = new TestLooper();
        mAlarmManager = new TestAlarmManager();
        mWifiMonitor = new MockWifiMonitor();
        mResources = new MockResources();

        when(mWifiNative.getInterfaceName()).thenReturn("a_test_interface_name");
        when(mContext.getSystemService(Context.ALARM_SERVICE))
                .thenReturn(mAlarmManager.getAlarmManager());
        when(mContext.getResources()).thenReturn(mResources);
        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
    }

    /**
     * Verify that the HW disconnected PNO scan triggers a wificond PNO scan and invokes the
     * OnPnoNetworkFound callback when the scan results are received.
     */
    @Test
    public void startHwDisconnectedPnoScan() {
        createScannerWithHwPnoScanSupport();

        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
        ScanResults scanResults = createDummyScanResults(false);

        InOrder order = inOrder(pnoEventHandler, mWifiNative);
        // Start PNO scan
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
        expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
        verifyNoMoreInteractions(pnoEventHandler);
    }

    /**
     * Verify that we pause & resume HW PNO scan when a single scan is scheduled and invokes the
     * OnPnoNetworkFound callback when the scan results are received.
     */
    @Test
    public void pauseResumeHwDisconnectedPnoScanForSingleScan() {
        createScannerWithHwPnoScanSupport();

        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
        WifiNative.ScanSettings settings = createDummyScanSettings();
        ScanResults scanResults = createDummyScanResults(true);

        InOrder order = inOrder(eventHandler, mWifiNative);
        // Start PNO scan
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
        // Start single scan
        assertTrue(mScanner.startSingleScan(settings, eventHandler));
        // Verify that the PNO scan was paused and single scan runs successfully
        expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), scanResults);
        verifyNoMoreInteractions(eventHandler);

        order = inOrder(pnoEventHandler, mWifiNative);
        // Resume PNO scan after the single scan results are received and PNO monitor debounce
        // alarm fires.
        assertTrue("dispatch pno monitor alarm",
                mAlarmManager.dispatch(
                        WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
        assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
        // Now verify that PNO scan is resumed successfully
        expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
        verifyNoMoreInteractions(pnoEventHandler);
    }

    /**
     * Verify that the SW disconnected PNO scan triggers a background scan and invokes the
     * background scan callbacks when scan results are received.
     */
    @Test
    public void startSwDisconnectedPnoScan() {
        createScannerWithSwPnoScanSupport();
        doSuccessfulSwPnoScanTest(false);
    }

    /**
     * Verify that the HW connected PNO scan triggers a background scan and invokes the
     * background scan callbacks when scan results are received.
     */
    @Test
    public void startHwConnectedPnoScan() {
        createScannerWithHwPnoScanSupport();
        doSuccessfulSwPnoScanTest(true);
    }

    /**
     * Verify that the SW connected PNO scan triggers a background scan and invokes the
     * background scan callbacks when scan results are received.
     */
    @Test
    public void startSwConnectedPnoScan() {
        createScannerWithSwPnoScanSupport();
        doSuccessfulSwPnoScanTest(true);
    }

    /**
     * Verify that the HW PNO delayed failure cleans up the scan settings cleanly.
     * 1. Start Hw PNO.
     * 2. Start Single Scan which should pause PNO scan.
     * 3. Fail the PNO scan resume and verify that the OnPnoScanFailed callback is invoked.
     * 4. Now restart a new PNO scan to ensure that the failure was cleanly handled.
     */
    @Test
    public void delayedHwDisconnectedPnoScanFailure() {
        createScannerWithHwPnoScanSupport();

        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
        WifiNative.ScanSettings settings = createDummyScanSettings();
        ScanResults scanResults = createDummyScanResults(true);

        InOrder order = inOrder(eventHandler, mWifiNative);
        // Start PNO scan
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
        // Start single scan
        assertTrue(mScanner.startSingleScan(settings, eventHandler));
        // Verify that the PNO scan was paused and single scan runs successfully
        expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), scanResults);
        verifyNoMoreInteractions(eventHandler);

        // Fail the PNO resume and check that the OnPnoScanFailed callback is invoked.
        order = inOrder(pnoEventHandler, mWifiNative);
        when(mWifiNative.startPnoScan(any(WifiNative.PnoSettings.class))).thenReturn(false);
        assertTrue("dispatch pno monitor alarm",
                mAlarmManager.dispatch(
                        WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
        assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
        order.verify(pnoEventHandler).onPnoScanFailed();
        verifyNoMoreInteractions(pnoEventHandler);

        // Add a new PNO scan request
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
        assertTrue("dispatch pno monitor alarm",
                mAlarmManager.dispatch(
                        WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
        assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
        expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
        verifyNoMoreInteractions(pnoEventHandler);
    }

    /**
     * Verify that the HW PNO scan stop failure still resets the PNO scan state.
     * 1. Start Hw PNO.
     * 2. Stop Hw PNO scan which raises a stop command to WifiNative which is failed.
     * 3. Now restart a new PNO scan to ensure that the failure was cleanly handled.
     */
    @Test
    public void ignoreHwDisconnectedPnoScanStopFailure() {
        createScannerWithHwPnoScanSupport();

        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);

        // Start PNO scan
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);

        // Fail the PNO stop.
        when(mWifiNative.stopPnoScan()).thenReturn(false);
        assertTrue(mScanner.resetHwPnoList());
        assertTrue("dispatch pno monitor alarm",
                mAlarmManager.dispatch(
                        WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
        mLooper.dispatchAll();
        verify(mWifiNative).stopPnoScan();

        // Add a new PNO scan request and ensure it runs successfully.
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
        assertTrue("dispatch pno monitor alarm",
                mAlarmManager.dispatch(
                        WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
        mLooper.dispatchAll();
        InOrder order = inOrder(pnoEventHandler, mWifiNative);
        ScanResults scanResults = createDummyScanResults(false);
        expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
        verifyNoMoreInteractions(pnoEventHandler);
    }

    /**
     * Verify that the HW PNO scan is forcefully stopped (bypass debounce logic) and restarted when
     * settings change.
     * 1. Start Hw PNO.
     * 2. Stop Hw PNO .
     * 3. Now restart a new PNO scan with different settings.
     * 4. Ensure that the stop was issued before we start again.
     */
    @Test
    public void forceRestartHwDisconnectedPnoScanWhenSettingsChange() {
        createScannerWithHwPnoScanSupport();

        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
        InOrder order = inOrder(pnoEventHandler, mWifiNative);

        // Start PNO scan
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
        expectHwDisconnectedPnoScanStart(order, pnoSettings);

        // Stop PNO now. This should trigger the debounce timer and not stop PNO.
        assertTrue(mScanner.resetHwPnoList());
        assertTrue(mAlarmManager.isPending(
                WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
        order.verify(mWifiNative, never()).stopPnoScan();

        // Now restart PNO scan with an extra network in settings.
        pnoSettings.networkList =
                Arrays.copyOf(pnoSettings.networkList, pnoSettings.networkList.length + 1);
        pnoSettings.networkList[pnoSettings.networkList.length - 1] =
                createDummyPnoNetwork("ssid_pno_new");
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);

        // This should bypass the debounce timer and stop PNO scan immediately and then start
        // a new debounce timer for the start.
        order.verify(mWifiNative).stopPnoScan();

        // Trigger the debounce timer and ensure we start PNO scan again.
        mAlarmManager.dispatch(WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG);
        mLooper.dispatchAll();
        order.verify(mWifiNative).startPnoScan(pnoSettings);
    }

    /**
     * Verify that the HW PNO scan is not forcefully stopped (bypass debounce logic) when
     * settings don't change.
     * 1. Start Hw PNO.
     * 2. Stop Hw PNO .
     * 3. Now restart a new PNO scan with same settings.
     * 4. Ensure that the stop was never issued.
     */
    @Test
    public void noForceRestartHwDisconnectedPnoScanWhenNoSettingsChange() {
        createScannerWithHwPnoScanSupport();

        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
        InOrder order = inOrder(pnoEventHandler, mWifiNative);

        // Start PNO scan
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
        expectHwDisconnectedPnoScanStart(order, pnoSettings);

        // Stop PNO now. This should trigger the debounce timer and not stop PNO.
        assertTrue(mScanner.resetHwPnoList());
        assertTrue(mAlarmManager.isPending(
                WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
        order.verify(mWifiNative, never()).stopPnoScan();

        // Now restart PNO scan with the same settings.
        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);

        // Trigger the debounce timer and ensure that we neither stop/start.
        mLooper.dispatchAll();
        order.verify(mWifiNative, never()).startPnoScan(any(WifiNative.PnoSettings.class));
        order.verify(mWifiNative, never()).stopPnoScan();
    }

    private void doSuccessfulSwPnoScanTest(boolean isConnectedPno) {
        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(isConnectedPno);
        WifiNative.ScanEventHandler scanEventHandler = mock(WifiNative.ScanEventHandler.class);
        WifiNative.ScanSettings scanSettings = createDummyScanSettings();
        ScanResults scanResults = createDummyScanResults(false);

        InOrder order = inOrder(scanEventHandler, mWifiNative);

        // Start PNO scan
        startSuccessfulPnoScan(scanSettings, pnoSettings, scanEventHandler, pnoEventHandler);

        expectSuccessfulSwPnoScan(order, scanEventHandler, scanResults);

        verifyNoMoreInteractions(pnoEventHandler);
    }

    private void createScannerWithHwPnoScanSupport() {
        mResources.setBoolean(R.bool.config_wifi_background_scan_support, true);
        mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
                mLooper.getLooper(), mClock);
    }

    private void createScannerWithSwPnoScanSupport() {
        mResources.setBoolean(R.bool.config_wifi_background_scan_support, false);
        mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
                mLooper.getLooper(), mClock);
    }

    private WifiNative.PnoNetwork createDummyPnoNetwork(String ssid) {
        WifiNative.PnoNetwork pnoNetwork = new WifiNative.PnoNetwork();
        pnoNetwork.ssid = ssid;
        return pnoNetwork;
    }

    private WifiNative.PnoSettings createDummyPnoSettings(boolean isConnected) {
        WifiNative.PnoSettings pnoSettings = new WifiNative.PnoSettings();
        pnoSettings.isConnected = isConnected;
        pnoSettings.networkList = new WifiNative.PnoNetwork[2];
        pnoSettings.networkList[0] = createDummyPnoNetwork("ssid_pno_1");
        pnoSettings.networkList[1] = createDummyPnoNetwork("ssid_pno_2");
        return pnoSettings;
    }

    private WifiNative.ScanSettings createDummyScanSettings() {
        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
                .withBasePeriod(10000)
                .withMaxApPerScan(10)
                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
                        WifiScanner.WIFI_BAND_24_GHZ)
                .build();
        return settings;
    }

    private ScanResults createDummyScanResults(boolean allChannelsScanned) {
        return ScanResults.create(0, allChannelsScanned, 2400, 2450, 2450, 2400, 2450, 2450, 2400,
                2450, 2450);
    }

    private void startSuccessfulPnoScan(WifiNative.ScanSettings scanSettings,
            WifiNative.PnoSettings pnoSettings, WifiNative.ScanEventHandler scanEventHandler,
            WifiNative.PnoEventHandler pnoEventHandler) {
        reset(mWifiNative);
        // Scans succeed
        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
        when(mWifiNative.startPnoScan(any(WifiNative.PnoSettings.class))).thenReturn(true);
        when(mWifiNative.stopPnoScan()).thenReturn(true);

        if (mScanner.isHwPnoSupported(pnoSettings.isConnected)) {
            // This should happen only for HW PNO scan
            assertTrue(mScanner.setHwPnoList(pnoSettings, pnoEventHandler));
        } else {
            // This should happen only for SW PNO scan
            assertTrue(mScanner.startBatchedScan(scanSettings, scanEventHandler));

        }
    }

    private Set<Integer> expectedBandScanFreqs(int band) {
        ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection();
        collection.addBand(band);
        return collection.getSupplicantScanFreqs();
    }

    /**
     * Verify that the PNO scan was successfully started.
     */
    private void expectHwDisconnectedPnoScanStart(InOrder order,
            WifiNative.PnoSettings pnoSettings) {
        // Verify  HW PNO scan started
        order.verify(mWifiNative).startPnoScan(any(WifiNative.PnoSettings.class));
    }

    /**
     *
     * 1. Verify that the PNO scan was successfully started.
     * 2. Send scan results and ensure that the |onPnoNetworkFound| callback was called.
     */
    private void expectSuccessfulHwDisconnectedPnoScan(InOrder order,
            WifiNative.PnoSettings pnoSettings, WifiNative.PnoEventHandler eventHandler,
            ScanResults scanResults) {
        expectHwDisconnectedPnoScanStart(order, pnoSettings);

        // Setup scan results
        when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());

        // Notify scan has finished
        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(),
                                 WifiMonitor.PNO_SCAN_RESULTS_EVENT);
        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());

        order.verify(eventHandler).onPnoNetworkFound(scanResults.getRawScanResults());
    }

    /**
     * Verify that the single scan results were delivered and that the PNO scan was paused and
     * resumed either side of it.
     */
    private void expectSuccessfulSingleScanWithHwPnoEnabled(InOrder order,
            WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScanFreqs,
            ScanResults scanResults) {
        // Pause PNO scan first
        order.verify(mWifiNative).stopPnoScan();

        order.verify(mWifiNative).scan(eq(expectedScanFreqs), any(Set.class));

        when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());

        // Notify scan has finished
        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());

        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
        assertScanDataEquals(scanResults.getScanData(), mScanner.getLatestSingleScanResults());
    }

    /**
     * Verify that the SW PNO scan was successfully started. This could either be disconnected
     * or connected PNO.
     * This is basically ensuring that the background scan runs successfully and returns the
     * expected result.
     */
    private void expectSuccessfulSwPnoScan(InOrder order,
            WifiNative.ScanEventHandler eventHandler, ScanResults scanResults) {

        // Verify scan started
        order.verify(mWifiNative).scan(any(Set.class), any(Set.class));

        // Make sure that HW PNO scan was not started
        verify(mWifiNative, never()).startPnoScan(any(WifiNative.PnoSettings.class));

        // Setup scan results
        when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());

        // Notify scan has finished
        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());

        // Verify background scan results delivered
        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
        WifiScanner.ScanData[] scanData = mScanner.getLatestBatchedScanResults(true);
        WifiScanner.ScanData lastScanData = scanData[scanData.length - 1];
        assertScanDataEquals(scanResults.getScanData(), lastScanData);
    }
}