NetworkStatsObserversTest.java revision 963e8ddf6d5ea3bc34216fa03fe24402bf13940a
1/*
2 * Copyright (C) 2016 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.net;
18
19import static android.net.ConnectivityManager.TYPE_MOBILE;
20import static android.net.ConnectivityManager.TYPE_WIFI;
21import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
22import static org.mockito.Matchers.any;
23import static org.mockito.Matchers.anyInt;
24import static org.mockito.Matchers.isA;
25import static org.mockito.Mockito.when;
26
27import static android.net.NetworkStats.SET_DEFAULT;
28import static android.net.NetworkStats.METERED_NO;
29import static android.net.NetworkStats.ROAMING_NO;
30import static android.net.NetworkStats.TAG_NONE;
31import static android.net.NetworkTemplate.buildTemplateMobileAll;
32import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
33import static android.net.TrafficStats.MB_IN_BYTES;
34import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
35
36import android.app.usage.NetworkStatsManager;
37import android.net.DataUsageRequest;
38import android.net.NetworkIdentity;
39import android.net.NetworkStats;
40import android.net.NetworkTemplate;
41import android.os.Handler;
42import android.os.HandlerThread;
43import android.os.IBinder;
44import android.os.Process;
45
46import android.os.ConditionVariable;
47import android.os.Looper;
48import android.os.Messenger;
49import android.os.Message;
50import android.os.UserHandle;
51import android.telephony.TelephonyManager;
52import android.util.ArrayMap;
53
54import com.android.internal.net.VpnInfo;
55import com.android.server.net.NetworkStatsService;
56import com.android.server.net.NetworkStatsServiceTest.IdleableHandlerThread;
57import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
58
59import java.util.ArrayList;
60import java.util.Objects;
61import java.util.List;
62
63import junit.framework.TestCase;
64
65import org.mockito.Mock;
66import org.mockito.Mockito;
67import org.mockito.MockitoAnnotations;
68
69/**
70 * Tests for {@link NetworkStatsObservers}.
71 */
72public class NetworkStatsObserversTest extends TestCase {
73    private static final String TEST_IFACE = "test0";
74    private static final String TEST_IFACE2 = "test1";
75    private static final long TEST_START = 1194220800000L;
76
77    private static final String IMSI_1 = "310004";
78    private static final String IMSI_2 = "310260";
79    private static final String TEST_SSID = "AndroidAP";
80
81    private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
82    private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
83    private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
84
85    private static final int UID_RED = UserHandle.PER_USER_RANGE + 1;
86    private static final int UID_BLUE = UserHandle.PER_USER_RANGE + 2;
87    private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
88    private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
89
90    private static final long WAIT_TIMEOUT = 500;  // 1/2 sec
91    private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
92    private static final long BASE_BYTES = 7 * MB_IN_BYTES;
93    private static final int INVALID_TYPE = -1;
94
95    private static final VpnInfo[] VPN_INFO = new VpnInfo[0];
96
97    private long mElapsedRealtime;
98
99    private IdleableHandlerThread mObserverHandlerThread;
100    private Handler mObserverNoopHandler;
101
102    private LatchedHandler mHandler;
103    private ConditionVariable mCv;
104
105    private NetworkStatsObservers mStatsObservers;
106    private Messenger mMessenger;
107    private ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
108    private ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
109
110    @Mock private IBinder mockBinder;
111
112    @Override
113    public void setUp() throws Exception {
114        super.setUp();
115        MockitoAnnotations.initMocks(this);
116
117        mObserverHandlerThread = new IdleableHandlerThread("HandlerThread");
118        mObserverHandlerThread.start();
119        final Looper observerLooper = mObserverHandlerThread.getLooper();
120        mStatsObservers = new NetworkStatsObservers() {
121            @Override
122            protected Looper getHandlerLooperLocked() {
123                return observerLooper;
124            }
125        };
126
127        mCv = new ConditionVariable();
128        mHandler = new LatchedHandler(Looper.getMainLooper(), mCv);
129        mMessenger = new Messenger(mHandler);
130
131        mActiveIfaces = new ArrayMap<>();
132        mActiveUidIfaces = new ArrayMap<>();
133    }
134
135    public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
136        long thresholdTooLowBytes = 1L;
137        DataUsageRequest inputRequest = new DataUsageRequest(
138                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdTooLowBytes);
139
140        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
141                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
142        assertTrue(request.requestId > 0);
143        assertTrue(Objects.equals(sTemplateWifi, request.template));
144        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
145    }
146
147    public void testRegister_highThreshold_accepted() throws Exception {
148        long highThresholdBytes = 2 * THRESHOLD_BYTES;
149        DataUsageRequest inputRequest = new DataUsageRequest(
150                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, highThresholdBytes);
151
152        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
153                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
154        assertTrue(request.requestId > 0);
155        assertTrue(Objects.equals(sTemplateWifi, request.template));
156        assertEquals(highThresholdBytes, request.thresholdInBytes);
157    }
158
159    public void testRegister_twoRequests_twoIds() throws Exception {
160        DataUsageRequest inputRequest = new DataUsageRequest(
161                DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, THRESHOLD_BYTES);
162
163        DataUsageRequest request1 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
164                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
165        assertTrue(request1.requestId > 0);
166        assertTrue(Objects.equals(sTemplateWifi, request1.template));
167        assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
168
169        DataUsageRequest request2 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
170                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
171        assertTrue(request2.requestId > request1.requestId);
172        assertTrue(Objects.equals(sTemplateWifi, request2.template));
173        assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
174    }
175
176    public void testUnregister_unknownRequest_noop() throws Exception {
177        DataUsageRequest unknownRequest = new DataUsageRequest(
178                123456 /* id */, sTemplateWifi, THRESHOLD_BYTES);
179
180        mStatsObservers.unregister(unknownRequest, UID_RED);
181    }
182
183    public void testUnregister_knownRequest_releasesCaller() throws Exception {
184        DataUsageRequest inputRequest = new DataUsageRequest(
185                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
186
187        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
188                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
189        assertTrue(request.requestId > 0);
190        assertTrue(Objects.equals(sTemplateImsi1, request.template));
191        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
192        Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
193
194        mStatsObservers.unregister(request, Process.SYSTEM_UID);
195        waitForObserverToIdle();
196
197        Mockito.verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
198    }
199
200    public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
201        DataUsageRequest inputRequest = new DataUsageRequest(
202                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
203
204        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
205                UID_RED, NetworkStatsAccess.Level.DEVICE);
206        assertTrue(request.requestId > 0);
207        assertTrue(Objects.equals(sTemplateImsi1, request.template));
208        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
209        Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
210
211        mStatsObservers.unregister(request, UID_BLUE);
212        waitForObserverToIdle();
213
214        Mockito.verifyZeroInteractions(mockBinder);
215    }
216
217    public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
218        DataUsageRequest inputRequest = new DataUsageRequest(
219                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
220
221        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
222                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
223        assertTrue(request.requestId > 0);
224        assertTrue(Objects.equals(sTemplateImsi1, request.template));
225        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
226
227        NetworkIdentitySet identSet = new NetworkIdentitySet();
228        identSet.add(new NetworkIdentity(
229                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
230                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
231        mActiveIfaces.put(TEST_IFACE, identSet);
232
233        // Baseline
234        NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
235                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
236        NetworkStats uidSnapshot = null;
237
238        mStatsObservers.updateStats(
239                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
240                VPN_INFO, TEST_START);
241        waitForObserverToIdle();
242
243        assertTrue(mCv.block(WAIT_TIMEOUT));
244        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
245    }
246
247    public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
248        DataUsageRequest inputRequest = new DataUsageRequest(
249                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
250
251        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
252                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
253        assertTrue(request.requestId > 0);
254        assertTrue(Objects.equals(sTemplateImsi1, request.template));
255        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
256
257        NetworkIdentitySet identSet = new NetworkIdentitySet();
258        identSet.add(new NetworkIdentity(
259                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
260                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
261        mActiveIfaces.put(TEST_IFACE, identSet);
262
263        // Baseline
264        NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
265                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
266        NetworkStats uidSnapshot = null;
267        mStatsObservers.updateStats(
268                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
269                VPN_INFO, TEST_START);
270
271        // Delta
272        xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
273                .addIfaceValues(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L);
274        mStatsObservers.updateStats(
275                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
276                VPN_INFO, TEST_START);
277        waitForObserverToIdle();
278
279        assertTrue(mCv.block(WAIT_TIMEOUT));
280        mCv.block(WAIT_TIMEOUT);
281        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
282    }
283
284    public void testUpdateStats_deviceAccess_notifies() throws Exception {
285        DataUsageRequest inputRequest = new DataUsageRequest(
286                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
287
288        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
289                Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
290        assertTrue(request.requestId > 0);
291        assertTrue(Objects.equals(sTemplateImsi1, request.template));
292        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
293
294        NetworkIdentitySet identSet = new NetworkIdentitySet();
295        identSet.add(new NetworkIdentity(
296                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
297                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
298        mActiveIfaces.put(TEST_IFACE, identSet);
299
300        // Baseline
301        NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
302                .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
303        NetworkStats uidSnapshot = null;
304        mStatsObservers.updateStats(
305                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
306                VPN_INFO, TEST_START);
307
308        // Delta
309        xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
310                .addIfaceValues(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L,
311                        BASE_BYTES + THRESHOLD_BYTES, 22L);
312        mStatsObservers.updateStats(
313                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
314                VPN_INFO, TEST_START);
315        waitForObserverToIdle();
316
317        assertTrue(mCv.block(WAIT_TIMEOUT));
318        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
319    }
320
321    public void testUpdateStats_defaultAccess_notifiesSameUid() throws Exception {
322        DataUsageRequest inputRequest = new DataUsageRequest(
323                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
324
325        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
326                UID_RED, NetworkStatsAccess.Level.DEFAULT);
327        assertTrue(request.requestId > 0);
328        assertTrue(Objects.equals(sTemplateImsi1, request.template));
329        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
330
331        NetworkIdentitySet identSet = new NetworkIdentitySet();
332        identSet.add(new NetworkIdentity(
333                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
334                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
335        mActiveUidIfaces.put(TEST_IFACE, identSet);
336
337        // Baseline
338        NetworkStats xtSnapshot = null;
339        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
340                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
341                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
342        mStatsObservers.updateStats(
343                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
344                VPN_INFO, TEST_START);
345
346        // Delta
347        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
348                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
349                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
350        mStatsObservers.updateStats(
351                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
352                VPN_INFO, TEST_START);
353        waitForObserverToIdle();
354
355        assertTrue(mCv.block(WAIT_TIMEOUT));
356        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
357    }
358
359    public void testUpdateStats_defaultAccess_usageOtherUid_doesNotNotify() throws Exception {
360        DataUsageRequest inputRequest = new DataUsageRequest(
361                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
362
363        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
364                UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
365        assertTrue(request.requestId > 0);
366        assertTrue(Objects.equals(sTemplateImsi1, request.template));
367        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
368
369        NetworkIdentitySet identSet = new NetworkIdentitySet();
370        identSet.add(new NetworkIdentity(
371                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
372                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
373        mActiveUidIfaces.put(TEST_IFACE, identSet);
374
375        // Baseline
376        NetworkStats xtSnapshot = null;
377        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
378                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
379                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
380        mStatsObservers.updateStats(
381                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
382                VPN_INFO, TEST_START);
383
384        // Delta
385        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
386                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
387                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
388        mStatsObservers.updateStats(
389                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
390                VPN_INFO, TEST_START);
391        waitForObserverToIdle();
392
393        assertTrue(mCv.block(WAIT_TIMEOUT));
394        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
395    }
396
397    public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
398        DataUsageRequest inputRequest = new DataUsageRequest(
399                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
400
401        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
402                UID_BLUE, NetworkStatsAccess.Level.USER);
403        assertTrue(request.requestId > 0);
404        assertTrue(Objects.equals(sTemplateImsi1, request.template));
405        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
406
407        NetworkIdentitySet identSet = new NetworkIdentitySet();
408        identSet.add(new NetworkIdentity(
409                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
410                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
411        mActiveUidIfaces.put(TEST_IFACE, identSet);
412
413        // Baseline
414        NetworkStats xtSnapshot = null;
415        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
416                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
417                        BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
418        mStatsObservers.updateStats(
419                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
420                VPN_INFO, TEST_START);
421
422        // Delta
423        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
424                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
425                        BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
426        mStatsObservers.updateStats(
427                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
428                VPN_INFO, TEST_START);
429        waitForObserverToIdle();
430
431        assertTrue(mCv.block(WAIT_TIMEOUT));
432        assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
433    }
434
435    public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
436        DataUsageRequest inputRequest = new DataUsageRequest(
437                DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
438
439        DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
440                UID_RED, NetworkStatsAccess.Level.USER);
441        assertTrue(request.requestId > 0);
442        assertTrue(Objects.equals(sTemplateImsi1, request.template));
443        assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
444
445        NetworkIdentitySet identSet = new NetworkIdentitySet();
446        identSet.add(new NetworkIdentity(
447                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
448                IMSI_1, null /* networkId */, false /* roaming */, true /* metered */));
449        mActiveUidIfaces.put(TEST_IFACE, identSet);
450
451        // Baseline
452        NetworkStats xtSnapshot = null;
453        NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
454                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
455                        ROAMING_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
456        mStatsObservers.updateStats(
457                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
458                VPN_INFO, TEST_START);
459
460        // Delta
461        uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
462                .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
463                        ROAMING_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES,
464                        2L, 0L);
465        mStatsObservers.updateStats(
466                xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
467                VPN_INFO, TEST_START);
468        waitForObserverToIdle();
469
470        assertTrue(mCv.block(WAIT_TIMEOUT));
471        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
472    }
473
474    private void waitForObserverToIdle() {
475        // Send dummy message to make sure that any previous message has been handled
476        mHandler.sendMessage(mHandler.obtainMessage(-1));
477        mObserverHandlerThread.waitForIdle(WAIT_TIMEOUT);
478    }
479}
480