diff options
3 files changed, 205 insertions, 4 deletions
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 56a57348d..dd1fb4492 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.InterfaceConfiguration; import android.net.MacAddress; +import android.net.TrafficStats; import android.net.apf.ApfCapabilities; import android.net.wifi.RttManager; import android.net.wifi.RttManager.ResponderConfig; @@ -2477,6 +2478,26 @@ public class WifiNative { } /** + * Get the tx packet counts for the interface. + * + * @param ifaceName Name of the interface. + * @return tx packet counts + */ + public long getTxPackets(@NonNull String ifaceName) { + return TrafficStats.getTxPackets(ifaceName); + } + + /** + * Get the rx packet counts for the interface. + * + * @param ifaceName Name of the interface + * @return rx packet counts + */ + public long getRxPackets(@NonNull String ifaceName) { + return TrafficStats.getRxPackets(ifaceName); + } + + /** * Start sending the specified keep alive packets periodically. * * @param ifaceName Name of the interface. diff --git a/service/java/com/android/server/wifi/WifiTrafficPoller.java b/service/java/com/android/server/wifi/WifiTrafficPoller.java index cd6c72d57..bcb625ed6 100644 --- a/service/java/com/android/server/wifi/WifiTrafficPoller.java +++ b/service/java/com/android/server/wifi/WifiTrafficPoller.java @@ -24,7 +24,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.NetworkInfo; -import android.net.TrafficStats; import android.net.wifi.WifiManager; import android.os.Handler; import android.os.Looper; @@ -75,7 +74,8 @@ public class WifiTrafficPoller { private boolean mVerboseLoggingEnabled = false; - WifiTrafficPoller(Context context, Looper looper, WifiNative wifiNative) { + WifiTrafficPoller(@NonNull Context context, @NonNull Looper looper, + @NonNull WifiNative wifiNative) { mTrafficHandler = new TrafficHandler(looper); mWifiNative = wifiNative; @@ -195,8 +195,8 @@ public class WifiTrafficPoller { long preTxPkts = mTxPkts, preRxPkts = mRxPkts; int dataActivity = WifiManager.DATA_ACTIVITY_NONE; - mTxPkts = TrafficStats.getTxPackets(ifaceName); - mRxPkts = TrafficStats.getRxPackets(ifaceName); + mTxPkts = mWifiNative.getTxPackets(ifaceName); + mRxPkts = mWifiNative.getRxPackets(ifaceName); if (DBG) { Log.d(TAG, " packet count Tx=" diff --git a/tests/wifitests/src/com/android/server/wifi/WifiTrafficPollerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiTrafficPollerTest.java new file mode 100644 index 000000000..40281f8ba --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/WifiTrafficPollerTest.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2018 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; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.NetworkInfo; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.os.test.TestLooper; +import android.support.test.filters.SmallTest; + +/** + * Unit tests for {@link com.android.server.wifi.WifiTrafficPoller}. + */ +@SmallTest +public class WifiTrafficPollerTest { + public static final String TAG = "WifiTrafficPollerTest"; + + private TestLooper mLooper; + private Handler mHandler; + private WifiTrafficPoller mWifiTrafficPoller; + private BroadcastReceiver mReceiver; + private Intent mIntent; + private Messenger mMessenger; + private final static String IFNAME = "wlan0"; + private final static long DEFAULT_PACKET_COUNT = 10; + private final static long TX_PACKET_COUNT = 40; + private final static long RX_PACKET_COUNT = 50; + + final ArgumentCaptor<Message> mMessageCaptor = ArgumentCaptor.forClass(Message.class); + final ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + @Mock Context mContext; + @Mock WifiNative mWifiNative; + @Mock NetworkInfo mNetworkInfo; + + /** + * Called before each test + */ + @Before + public void setUp() throws Exception { + // Ensure looper exists + mLooper = new TestLooper(); + mHandler = spy(new Handler(mLooper.getLooper())); + mMessenger = new Messenger(mHandler); + MockitoAnnotations.initMocks(this); + + when(mWifiNative.getTxPackets(any(String.class))).thenReturn(DEFAULT_PACKET_COUNT, + TX_PACKET_COUNT); + when(mWifiNative.getRxPackets(any(String.class))).thenReturn(DEFAULT_PACKET_COUNT, + RX_PACKET_COUNT); + when(mWifiNative.getClientInterfaceName()).thenReturn(IFNAME); + + mWifiTrafficPoller = new WifiTrafficPoller(mContext, mLooper.getLooper(), mWifiNative); + // Verify the constructor registers broadcast receiver with the collect intent filters. + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), argThat( + intentFilter -> intentFilter.hasAction(WifiManager.NETWORK_STATE_CHANGED_ACTION) && + intentFilter.hasAction(Intent.ACTION_SCREEN_ON) && + intentFilter.hasAction(Intent.ACTION_SCREEN_OFF))); + mReceiver = mBroadcastReceiverCaptor.getValue(); + + // For the fist call, this is required to set the DEFAULT_PACKET_COUNT to mTxPkts and + // mRxPkts in WifiTrafficPoll Object. + triggerForUpdatedInformationOfData(Intent.ACTION_SCREEN_ON, + NetworkInfo.DetailedState.CONNECTED); + } + + private void registerClient() { + // Register Client to verify that Tx/RX packet message is properly received. + mWifiTrafficPoller.addClient(mMessenger); + mLooper.dispatchAll(); + } + + private void triggerForUpdatedInformationOfData(String actionScreen, + NetworkInfo.DetailedState networkState) { + when(mNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.DISCONNECTED); + mIntent = new Intent(actionScreen); + mReceiver.onReceive(mContext, mIntent); + mLooper.dispatchAll(); + + when(mNetworkInfo.getDetailedState()).thenReturn(networkState); + mIntent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mIntent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo); + mReceiver.onReceive(mContext, mIntent); + mLooper.dispatchAll(); + } + + /** + * Verify that StartTrafficStatsPolling should not happen in case a network is not connected + */ + @Test + public void testNotStartTrafficStatsPollingWithDisconnected() { + registerClient(); + triggerForUpdatedInformationOfData(Intent.ACTION_SCREEN_ON, + NetworkInfo.DetailedState.DISCONNECTED); + + // Client should not get any message when the network is disconnected + verify(mHandler, never()).handleMessage(any(Message.class)); + } + + /** + * Verify that StartTrafficStatsPolling should happen in case screen is on and rx/tx packets are + * available. + */ + @Test + public void testStartTrafficStatsPollingWithScreenOn() { + registerClient(); + triggerForUpdatedInformationOfData(Intent.ACTION_SCREEN_ON, + NetworkInfo.DetailedState.CONNECTED); + + // Client should get the DATA_ACTIVITY_NOTIFICATION + verify(mHandler).handleMessage(mMessageCaptor.capture()); + assertEquals(WifiManager.DATA_ACTIVITY_NOTIFICATION, mMessageCaptor.getValue().what); + } + + /** + * Verify that StartTrafficStatsPolling should not happen in case screen is off. + */ + @Test + public void testNotStartTrafficStatsPollingWithScreenOff() { + registerClient(); + triggerForUpdatedInformationOfData(Intent.ACTION_SCREEN_OFF, + NetworkInfo.DetailedState.CONNECTED); + + verify(mNetworkInfo, atLeastOnce()).getDetailedState(); + mLooper.dispatchAll(); + + // Client should not get any message when the screen is off + verify(mHandler, never()).handleMessage(any(Message.class)); + } + + /** + * Verify that remove client message should be handled + */ + @Test + public void testRemoveClient() { + registerClient(); + mWifiTrafficPoller.removeClient(mMessenger); + mLooper.dispatchAll(); + + triggerForUpdatedInformationOfData(Intent.ACTION_SCREEN_ON, + NetworkInfo.DetailedState.CONNECTED); + + // Client should not get any message after the client is removed. + verify(mHandler, never()).handleMessage(any(Message.class)); + } +} |