| /* |
| * Copyright (C) 2011 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; |
| |
| import static android.net.NetworkStats.SET_DEFAULT; |
| import static android.net.NetworkStats.TAG_NONE; |
| import static android.net.NetworkStats.UID_ALL; |
| import static org.easymock.EasyMock.createMock; |
| import static org.easymock.EasyMock.eq; |
| import static org.easymock.EasyMock.expect; |
| import static org.easymock.EasyMock.expectLastCall; |
| import static org.easymock.EasyMock.isA; |
| import static org.easymock.EasyMock.replay; |
| import static org.easymock.EasyMock.reset; |
| import static org.easymock.EasyMock.verify; |
| |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.net.INetworkManagementEventObserver; |
| import android.net.NetworkStats; |
| import android.net.ThrottleManager; |
| import android.os.IBinder; |
| import android.os.INetworkManagementService; |
| import android.os.ServiceManager; |
| import android.os.SystemClock; |
| import android.provider.Settings; |
| import android.test.AndroidTestCase; |
| import android.test.suitebuilder.annotation.LargeTest; |
| import android.test.suitebuilder.annotation.Suppress; |
| import android.text.format.DateUtils; |
| import android.util.Log; |
| import android.util.TrustedTime; |
| |
| import java.util.concurrent.Future; |
| |
| /** |
| * Tests for {@link ThrottleService}. |
| */ |
| @LargeTest |
| public class ThrottleServiceTest extends AndroidTestCase { |
| private static final String TAG = "ThrottleServiceTest"; |
| |
| private static final long MB_IN_BYTES = 1024 * 1024; |
| |
| private static final int TEST_KBITPS = 222; |
| private static final int TEST_RESET_DAY = 11; |
| |
| private static final String TEST_IFACE = "test0"; |
| |
| private BroadcastInterceptingContext mWatchingContext; |
| private INetworkManagementService mMockNMService; |
| private TrustedTime mMockTime; |
| |
| private ThrottleService mThrottleService; |
| |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| |
| mWatchingContext = new BroadcastInterceptingContext(getContext()); |
| |
| mMockNMService = createMock(INetworkManagementService.class); |
| mMockTime = createMock(TrustedTime.class); |
| |
| mThrottleService = new ThrottleService( |
| mWatchingContext, mMockNMService, mMockTime, TEST_IFACE); |
| } |
| |
| @Override |
| public void tearDown() throws Exception { |
| mWatchingContext = null; |
| mMockNMService = null; |
| |
| mThrottleService.shutdown(); |
| mThrottleService = null; |
| |
| clearThrottlePolicy(); |
| |
| super.tearDown(); |
| } |
| |
| public void testNoPolicyNotThrottled() throws Exception { |
| expectTimeCurrent(); |
| expectSystemReady(); |
| |
| // provide stats without policy, verify not throttled |
| expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(-1, -1); |
| |
| replay(mMockTime, mMockNMService); |
| systemReady(); |
| verify(mMockTime, mMockNMService); |
| } |
| |
| public void testUnderLimitNotThrottled() throws Exception { |
| setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); |
| |
| expectTimeCurrent(); |
| expectSystemReady(); |
| |
| // provide stats under limits, and verify not throttled |
| expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(-1, -1); |
| |
| replay(mMockTime, mMockNMService); |
| systemReady(); |
| verify(mMockTime, mMockNMService); |
| } |
| |
| public void testOverLimitThrottled() throws Exception { |
| setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); |
| |
| expectTimeCurrent(); |
| expectSystemReady(); |
| |
| // provide stats over limits, and verify throttled |
| expectGetInterfaceCounter(500 * MB_IN_BYTES, 600 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); |
| |
| replay(mMockTime, mMockNMService); |
| systemReady(); |
| verify(mMockTime, mMockNMService); |
| } |
| |
| public void testUnderThenOverLimitThrottled() throws Exception { |
| setThrottlePolicy(201 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); |
| |
| expectTimeCurrent(); |
| expectSystemReady(); |
| |
| // provide stats right under 201MB limit, verify not throttled |
| expectGetInterfaceCounter(100 * MB_IN_BYTES, 100 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(-1, -1); |
| |
| replay(mMockTime, mMockNMService); |
| systemReady(); |
| verify(mMockTime, mMockNMService); |
| reset(mMockTime, mMockNMService); |
| |
| expectTimeCurrent(); |
| |
| // adjust usage to bump over limit, verify throttle kicks in |
| expectGetInterfaceCounter(105 * MB_IN_BYTES, 100 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); |
| |
| // and kick poll event which should throttle |
| replay(mMockTime, mMockNMService); |
| forceServicePoll(); |
| verify(mMockTime, mMockNMService); |
| } |
| |
| public void testUpdatedPolicyThrottled() throws Exception { |
| setThrottlePolicy(500 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); |
| |
| expectTimeCurrent(); |
| expectSystemReady(); |
| |
| // provide stats under limit, verify not throttled |
| expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(-1, -1); |
| |
| replay(mMockTime, mMockNMService); |
| systemReady(); |
| verify(mMockTime, mMockNMService); |
| reset(mMockTime, mMockNMService); |
| |
| expectTimeCurrent(); |
| |
| // provide same stats, but verify that modified policy will throttle |
| expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); |
| |
| replay(mMockTime, mMockNMService); |
| |
| // now adjust policy to bump usage over limit |
| setThrottlePolicy(5 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); |
| |
| // and wait for policy updated broadcast |
| mWatchingContext.nextBroadcastIntent(ThrottleManager.POLICY_CHANGED_ACTION).get(); |
| |
| verify(mMockTime, mMockNMService); |
| } |
| |
| public void testWithPolicyOverLimitThrottledAndRemovedAfterCycle() throws Exception { |
| setThrottlePolicy(90 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY); |
| |
| final long baseTime = System.currentTimeMillis(); |
| |
| expectTime(baseTime); |
| expectSystemReady(); |
| |
| // provide stats over limit, verify throttle kicks in |
| expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS); |
| |
| replay(mMockTime, mMockNMService); |
| systemReady(); |
| verify(mMockTime, mMockNMService); |
| reset(mMockTime, mMockNMService); |
| |
| // pretend that time has jumped forward two months |
| expectTime(baseTime + DateUtils.WEEK_IN_MILLIS * 8); |
| |
| // provide slightly updated stats, but verify throttle is removed |
| expectGetInterfaceCounter(60 * MB_IN_BYTES, 60 * MB_IN_BYTES); |
| expectSetInterfaceThrottle(-1, -1); |
| |
| // and kick poll event which should throttle |
| replay(mMockTime, mMockNMService); |
| forceServiceReset(); |
| verify(mMockTime, mMockNMService); |
| } |
| |
| @Suppress |
| public void testReturnStats() throws Exception { |
| final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); |
| final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b); |
| |
| // test is currently no-op, just exercises stats apis |
| Log.d(TAG, nmService.getNetworkStatsSummaryDev().toString()); |
| Log.d(TAG, nmService.getNetworkStatsSummaryXt().toString()); |
| Log.d(TAG, nmService.getNetworkStatsDetail().toString()); |
| } |
| |
| /** |
| * Persist the given {@link ThrottleService} policy into {@link Settings}. |
| */ |
| public void setThrottlePolicy(long thresholdBytes, int valueKbitps, int resetDay) { |
| final ContentResolver resolver = getContext().getContentResolver(); |
| Settings.Global.putLong(resolver, Settings.Global.THROTTLE_THRESHOLD_BYTES, thresholdBytes); |
| Settings.Global.putInt(resolver, Settings.Global.THROTTLE_VALUE_KBITSPS, valueKbitps); |
| Settings.Global.putInt(resolver, Settings.Global.THROTTLE_RESET_DAY, resetDay); |
| } |
| |
| /** |
| * Clear any {@link ThrottleService} policy from {@link Settings}. |
| */ |
| public void clearThrottlePolicy() { |
| final ContentResolver resolver = getContext().getContentResolver(); |
| Settings.Global.putString(resolver, Settings.Global.THROTTLE_THRESHOLD_BYTES, null); |
| Settings.Global.putString(resolver, Settings.Global.THROTTLE_VALUE_KBITSPS, null); |
| Settings.Global.putString(resolver, Settings.Global.THROTTLE_RESET_DAY, null); |
| } |
| |
| /** |
| * Expect any {@link TrustedTime} mock calls, and respond with |
| * {@link System#currentTimeMillis()}. |
| */ |
| public void expectTimeCurrent() throws Exception { |
| expectTime(System.currentTimeMillis()); |
| } |
| |
| /** |
| * Expect any {@link TrustedTime} mock calls, and respond with the given |
| * time in response to {@link TrustedTime#currentTimeMillis()}. |
| */ |
| public void expectTime(long currentTime) throws Exception { |
| expect(mMockTime.forceRefresh()).andReturn(false).anyTimes(); |
| expect(mMockTime.hasCache()).andReturn(true).anyTimes(); |
| expect(mMockTime.currentTimeMillis()).andReturn(currentTime).anyTimes(); |
| expect(mMockTime.getCacheAge()).andReturn(0L).anyTimes(); |
| expect(mMockTime.getCacheCertainty()).andReturn(0L).anyTimes(); |
| } |
| |
| /** |
| * Expect {@link ThrottleService#systemReady()} generated calls, such as |
| * connecting with {@link NetworkManagementService} mock. |
| */ |
| public void expectSystemReady() throws Exception { |
| mMockNMService.registerObserver(isA(INetworkManagementEventObserver.class)); |
| expectLastCall().atLeastOnce(); |
| } |
| |
| /** |
| * Expect {@link NetworkManagementService#getNetworkStatsSummaryDev()} mock |
| * calls, responding with the given counter values. |
| */ |
| public void expectGetInterfaceCounter(long rx, long tx) throws Exception { |
| // TODO: provide elapsedRealtime mock to match TimeAuthority |
| final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); |
| stats.addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, rx, 0L, tx, 0L, 0); |
| |
| expect(mMockNMService.getNetworkStatsSummaryDev()).andReturn(stats).atLeastOnce(); |
| } |
| |
| /** |
| * Expect {@link NetworkManagementService#setInterfaceThrottle} mock call |
| * with the specified parameters. |
| */ |
| public void expectSetInterfaceThrottle(int rx, int tx) throws Exception { |
| mMockNMService.setInterfaceThrottle(isA(String.class), eq(rx), eq(tx)); |
| expectLastCall().atLeastOnce(); |
| } |
| |
| /** |
| * Dispatch {@link ThrottleService#systemReady()} and block until finished. |
| */ |
| public void systemReady() throws Exception { |
| final Future<Intent> policyChanged = mWatchingContext.nextBroadcastIntent( |
| ThrottleManager.POLICY_CHANGED_ACTION); |
| final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent( |
| ThrottleManager.THROTTLE_POLL_ACTION); |
| |
| mThrottleService.systemReady(); |
| |
| // wait for everything to settle; for policy to update and for first poll |
| policyChanged.get(); |
| pollAction.get(); |
| } |
| |
| /** |
| * Dispatch {@link ThrottleService#dispatchPoll()} and block until finished. |
| */ |
| public void forceServicePoll() throws Exception { |
| // during systemReady() service already pushed a sticky broadcast, so we |
| // need to skip the immediate and wait for the updated sticky. |
| final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent( |
| ThrottleManager.THROTTLE_POLL_ACTION); |
| |
| mThrottleService.dispatchPoll(); |
| |
| pollAction.get(); |
| } |
| |
| /** |
| * Dispatch {@link ThrottleService#dispatchReset()} and block until finished. |
| */ |
| public void forceServiceReset() throws Exception { |
| // during systemReady() service already pushed a sticky broadcast, so we |
| // need to skip the immediate and wait for the updated sticky. |
| final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent( |
| ThrottleManager.THROTTLE_POLL_ACTION); |
| |
| mThrottleService.dispatchReset(); |
| |
| pollAction.get(); |
| } |
| } |