blob: f20d5e5e2ef90d1f7ff0161b8565effadc7d13ce [file] [log] [blame]
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -07001/*
2 * Copyright (C) 2011 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 com.android.server;
18
19import static org.easymock.EasyMock.createMock;
20import static org.easymock.EasyMock.eq;
21import static org.easymock.EasyMock.expect;
22import static org.easymock.EasyMock.expectLastCall;
23import static org.easymock.EasyMock.isA;
24import static org.easymock.EasyMock.replay;
25import static org.easymock.EasyMock.reset;
26import static org.easymock.EasyMock.verify;
27
28import com.google.common.collect.Lists;
29import com.google.common.util.concurrent.AbstractFuture;
30
31import android.content.ContentResolver;
32import android.content.Context;
33import android.content.ContextWrapper;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.net.INetworkManagementEventObserver;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070037import android.net.NetworkStats;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070038import android.net.ThrottleManager;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070039import android.os.IBinder;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070040import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070041import android.os.ServiceManager;
42import android.os.SystemClock;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070043import android.provider.Settings;
44import android.test.AndroidTestCase;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070045import android.test.suitebuilder.annotation.Suppress;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070046import android.text.format.DateUtils;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070047import android.util.Log;
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -070048import android.util.TrustedTime;
49
50import java.util.Iterator;
51import java.util.List;
52import java.util.concurrent.Future;
53
54/**
55 * Tests for {@link ThrottleService}.
56 */
57public class ThrottleServiceTest extends AndroidTestCase {
58 private static final String TAG = "ThrottleServiceTest";
59
60 private static final long MB_IN_BYTES = 1024 * 1024;
61
62 private static final int TEST_KBITPS = 222;
63 private static final int TEST_RESET_DAY = 11;
64
65 private static final String TEST_IFACE = "test0";
66
67 private WatchingContext mWatchingContext;
68 private INetworkManagementService mMockNMService;
69 private TrustedTime mMockTime;
70
71 private ThrottleService mThrottleService;
72
73 @Override
74 public void setUp() throws Exception {
75 super.setUp();
76
77 mWatchingContext = new WatchingContext(getContext());
78
79 mMockNMService = createMock(INetworkManagementService.class);
80 mMockTime = createMock(TrustedTime.class);
81
82 mThrottleService = new ThrottleService(
83 mWatchingContext, mMockNMService, mMockTime, TEST_IFACE);
84 }
85
86 @Override
87 public void tearDown() throws Exception {
88 mWatchingContext = null;
89 mMockNMService = null;
90
91 mThrottleService.shutdown();
92 mThrottleService = null;
93
94 clearThrottlePolicy();
95
96 super.tearDown();
97 }
98
99 public void testNoPolicyNotThrottled() throws Exception {
100 expectTimeCurrent();
101 expectSystemReady();
102
103 // provide stats without policy, verify not throttled
104 expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES);
105 expectSetInterfaceThrottle(-1, -1);
106
107 replay(mMockTime, mMockNMService);
108 systemReady();
109 verify(mMockTime, mMockNMService);
110 }
111
112 public void testUnderLimitNotThrottled() throws Exception {
113 setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
114
115 expectTimeCurrent();
116 expectSystemReady();
117
118 // provide stats under limits, and verify not throttled
119 expectGetInterfaceCounter(1 * MB_IN_BYTES, 2 * MB_IN_BYTES);
120 expectSetInterfaceThrottle(-1, -1);
121
122 replay(mMockTime, mMockNMService);
123 systemReady();
124 verify(mMockTime, mMockNMService);
125 }
126
127 public void testOverLimitThrottled() throws Exception {
128 setThrottlePolicy(200 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
129
130 expectTimeCurrent();
131 expectSystemReady();
132
133 // provide stats over limits, and verify throttled
134 expectGetInterfaceCounter(500 * MB_IN_BYTES, 600 * MB_IN_BYTES);
135 expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
136
137 replay(mMockTime, mMockNMService);
138 systemReady();
139 verify(mMockTime, mMockNMService);
140 }
141
142 public void testUnderThenOverLimitThrottled() throws Exception {
143 setThrottlePolicy(201 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
144
145 expectTimeCurrent();
146 expectSystemReady();
147
148 // provide stats right under 201MB limit, verify not throttled
149 expectGetInterfaceCounter(100 * MB_IN_BYTES, 100 * MB_IN_BYTES);
150 expectSetInterfaceThrottle(-1, -1);
151
152 replay(mMockTime, mMockNMService);
153 systemReady();
154 verify(mMockTime, mMockNMService);
155 reset(mMockTime, mMockNMService);
156
157 expectTimeCurrent();
158
159 // adjust usage to bump over limit, verify throttle kicks in
160 expectGetInterfaceCounter(105 * MB_IN_BYTES, 100 * MB_IN_BYTES);
161 expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
162
163 // and kick poll event which should throttle
164 replay(mMockTime, mMockNMService);
165 forceServicePoll();
166 verify(mMockTime, mMockNMService);
167 }
168
169 public void testUpdatedPolicyThrottled() throws Exception {
170 setThrottlePolicy(500 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
171
172 expectTimeCurrent();
173 expectSystemReady();
174
175 // provide stats under limit, verify not throttled
176 expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES);
177 expectSetInterfaceThrottle(-1, -1);
178
179 replay(mMockTime, mMockNMService);
180 systemReady();
181 verify(mMockTime, mMockNMService);
182 reset(mMockTime, mMockNMService);
183
184 expectTimeCurrent();
185
186 // provide same stats, but verify that modified policy will throttle
187 expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES);
188 expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
189
190 replay(mMockTime, mMockNMService);
191
192 // now adjust policy to bump usage over limit
193 setThrottlePolicy(5 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
194
195 // and wait for policy updated broadcast
196 mWatchingContext.nextBroadcastIntent(ThrottleManager.POLICY_CHANGED_ACTION).get();
197
198 verify(mMockTime, mMockNMService);
199 }
200
201 public void testWithPolicyOverLimitThrottledAndRemovedAfterCycle() throws Exception {
202 setThrottlePolicy(90 * MB_IN_BYTES, TEST_KBITPS, TEST_RESET_DAY);
203
204 final long baseTime = System.currentTimeMillis();
205
206 expectTime(baseTime);
207 expectSystemReady();
208
209 // provide stats over limit, verify throttle kicks in
210 expectGetInterfaceCounter(50 * MB_IN_BYTES, 50 * MB_IN_BYTES);
211 expectSetInterfaceThrottle(TEST_KBITPS, TEST_KBITPS);
212
213 replay(mMockTime, mMockNMService);
214 systemReady();
215 verify(mMockTime, mMockNMService);
216 reset(mMockTime, mMockNMService);
217
218 // pretend that time has jumped forward two months
219 expectTime(baseTime + DateUtils.WEEK_IN_MILLIS * 8);
220
221 // provide slightly updated stats, but verify throttle is removed
222 expectGetInterfaceCounter(60 * MB_IN_BYTES, 60 * MB_IN_BYTES);
223 expectSetInterfaceThrottle(-1, -1);
224
225 // and kick poll event which should throttle
226 replay(mMockTime, mMockNMService);
227 forceServiceReset();
228 verify(mMockTime, mMockNMService);
229 }
230
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700231 @Suppress
232 public void testReturnStats() throws Exception {
233 final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
234 final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
235
236 // test is currently no-op, just exercises stats apis
237 Log.d(TAG, nmService.getNetworkStatsSummary().toString());
238 Log.d(TAG, nmService.getNetworkStatsDetail().toString());
239 }
240
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700241 /**
242 * Persist the given {@link ThrottleService} policy into {@link Settings}.
243 */
244 public void setThrottlePolicy(long thresholdBytes, int valueKbitps, int resetDay) {
245 final ContentResolver resolver = getContext().getContentResolver();
246 Settings.Secure.putLong(resolver, Settings.Secure.THROTTLE_THRESHOLD_BYTES, thresholdBytes);
247 Settings.Secure.putInt(resolver, Settings.Secure.THROTTLE_VALUE_KBITSPS, valueKbitps);
248 Settings.Secure.putInt(resolver, Settings.Secure.THROTTLE_RESET_DAY, resetDay);
249 }
250
251 /**
252 * Clear any {@link ThrottleService} policy from {@link Settings}.
253 */
254 public void clearThrottlePolicy() {
255 final ContentResolver resolver = getContext().getContentResolver();
256 Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_THRESHOLD_BYTES, null);
257 Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_VALUE_KBITSPS, null);
258 Settings.Secure.putString(resolver, Settings.Secure.THROTTLE_RESET_DAY, null);
259 }
260
261 /**
262 * Expect any {@link TrustedTime} mock calls, and respond with
263 * {@link System#currentTimeMillis()}.
264 */
265 public void expectTimeCurrent() throws Exception {
266 expectTime(System.currentTimeMillis());
267 }
268
269 /**
270 * Expect any {@link TrustedTime} mock calls, and respond with the given
271 * time in response to {@link TrustedTime#currentTimeMillis()}.
272 */
273 public void expectTime(long currentTime) throws Exception {
274 expect(mMockTime.forceRefresh()).andReturn(false).anyTimes();
275 expect(mMockTime.hasCache()).andReturn(true).anyTimes();
276 expect(mMockTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
277 expect(mMockTime.getCacheAge()).andReturn(0L).anyTimes();
278 expect(mMockTime.getCacheCertainty()).andReturn(0L).anyTimes();
279 }
280
281 /**
282 * Expect {@link ThrottleService#systemReady()} generated calls, such as
283 * connecting with {@link NetworkManagementService} mock.
284 */
285 public void expectSystemReady() throws Exception {
286 mMockNMService.registerObserver(isA(INetworkManagementEventObserver.class));
287 expectLastCall().atLeastOnce();
288 }
289
290 /**
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700291 * Expect {@link NetworkManagementService#getNetworkStatsSummary()} mock
292 * calls, responding with the given counter values.
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700293 */
294 public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700295 // TODO: provide elapsedRealtime mock to match TimeAuthority
296 final NetworkStats.Builder stats = new NetworkStats.Builder(
297 SystemClock.elapsedRealtime(), 1);
298 stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx);
299
300 expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats.build()).atLeastOnce();
Jeff Sharkeyb7342ac2011-04-25 23:44:11 -0700301 }
302
303 /**
304 * Expect {@link NetworkManagementService#setInterfaceThrottle} mock call
305 * with the specified parameters.
306 */
307 public void expectSetInterfaceThrottle(int rx, int tx) throws Exception {
308 mMockNMService.setInterfaceThrottle(isA(String.class), eq(rx), eq(tx));
309 expectLastCall().atLeastOnce();
310 }
311
312 /**
313 * Dispatch {@link ThrottleService#systemReady()} and block until finished.
314 */
315 public void systemReady() throws Exception {
316 final Future<Intent> policyChanged = mWatchingContext.nextBroadcastIntent(
317 ThrottleManager.POLICY_CHANGED_ACTION);
318 final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent(
319 ThrottleManager.THROTTLE_POLL_ACTION);
320
321 mThrottleService.systemReady();
322
323 // wait for everything to settle; for policy to update and for first poll
324 policyChanged.get();
325 pollAction.get();
326 }
327
328 /**
329 * Dispatch {@link ThrottleService#dispatchPoll()} and block until finished.
330 */
331 public void forceServicePoll() throws Exception {
332 // during systemReady() service already pushed a sticky broadcast, so we
333 // need to skip the immediate and wait for the updated sticky.
334 final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent(
335 ThrottleManager.THROTTLE_POLL_ACTION);
336
337 mThrottleService.dispatchPoll();
338
339 pollAction.get();
340 }
341
342 /**
343 * Dispatch {@link ThrottleService#dispatchReset()} and block until finished.
344 */
345 public void forceServiceReset() throws Exception {
346 // during systemReady() service already pushed a sticky broadcast, so we
347 // need to skip the immediate and wait for the updated sticky.
348 final Future<Intent> pollAction = mWatchingContext.nextBroadcastIntent(
349 ThrottleManager.THROTTLE_POLL_ACTION);
350
351 mThrottleService.dispatchReset();
352
353 pollAction.get();
354 }
355
356
357 /**
358 * {@link ContextWrapper} that can attach listeners for upcoming
359 * {@link Context#sendBroadcast(Intent)}.
360 */
361 private static class WatchingContext extends ContextWrapper {
362 private List<LocalBroadcastReceiver> mReceivers = Lists.newArrayList();
363
364 public class LocalBroadcastReceiver extends AbstractFuture<Intent> {
365 private IntentFilter mFilter;
366
367 public LocalBroadcastReceiver(IntentFilter filter) {
368 mFilter = filter;
369 }
370
371 public boolean dispatchBroadcast(Intent intent) {
372 if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) {
373 set(intent);
374 return true;
375 } else {
376 return false;
377 }
378 }
379 }
380
381 public WatchingContext(Context base) {
382 super(base);
383 }
384
385 public Future<Intent> nextBroadcastIntent(String action) {
386 return nextBroadcastIntent(new IntentFilter(action));
387 }
388
389 public Future<Intent> nextBroadcastIntent(IntentFilter filter) {
390 final LocalBroadcastReceiver receiver = new LocalBroadcastReceiver(filter);
391 synchronized (mReceivers) {
392 mReceivers.add(receiver);
393 }
394 return receiver;
395 }
396
397 @Override
398 public void sendBroadcast(Intent intent) {
399 synchronized (mReceivers) {
400 final Iterator<LocalBroadcastReceiver> i = mReceivers.iterator();
401 while (i.hasNext()) {
402 final LocalBroadcastReceiver receiver = i.next();
403 if (receiver.dispatchBroadcast(intent)) {
404 i.remove();
405 }
406 }
407 }
408 }
409
410 @Override
411 public void sendStickyBroadcast(Intent intent) {
412 sendBroadcast(intent);
413 }
414
415 @Override
416 public void removeStickyBroadcast(Intent intent) {
417 // ignored
418 }
419 }
420}