blob: 2f275c373f4b1aac8eafdae7359f0109159339eb [file] [log] [blame]
/*
* 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 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.getNetworkStatsSummary().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.Secure.putLong(resolver, Settings.Secure.THROTTLE_THRESHOLD_BYTES, thresholdBytes);
Settings.Secure.putInt(resolver, Settings.Secure.THROTTLE_VALUE_KBITSPS, valueKbitps);
Settings.Secure.putInt(resolver, Settings.Secure.THROTTLE_RESET_DAY, resetDay);
}
/**
* Clear any {@link ThrottleService} policy from {@link Settings}.
*/
public void clearThrottlePolicy() {
final ContentResolver resolver = getContext().getContentResolver();
Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_THRESHOLD_BYTES, null);
Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_VALUE_KBITSPS, null);
Settings.Secure.putString(resolver, Settings.Secure.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#getNetworkStatsSummary()} 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.addEntry(TEST_IFACE, NetworkStats.UID_ALL, NetworkStats.TAG_NONE, rx, tx);
expect(mMockNMService.getNetworkStatsSummary()).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();
}
}