1 /*
2  * Copyright (C) 2022 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 
17 package com.android.server.am;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 
23 import android.os.SystemClock;
24 
25 import org.junit.Before;
26 import org.junit.Test;
27 
28 /**
29  * Test class for {@link DropboxRateLimiter}.
30  *
31  * Build/Install/Run:
32  *  atest DropboxRateLimiterTest
33  */
34 public class DropboxRateLimiterTest {
35     private DropboxRateLimiter mRateLimiter;
36     private TestClock mClock;
37 
38     @Before
setUp()39     public void setUp() {
40         mClock = new TestClock();
41         mRateLimiter = new DropboxRateLimiter(mClock);
42     }
43 
44     @Test
testMultipleProcesses()45     public void testMultipleProcesses() {
46         // The first 5 entries should not be rate limited.
47         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
48         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
49         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
50         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
51         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
52         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
53         // Different processes and tags should not get rate limited either.
54         assertFalse(mRateLimiter.shouldRateLimit("tag", "process2").shouldRateLimit());
55         assertFalse(mRateLimiter.shouldRateLimit("tag2", "process").shouldRateLimit());
56         // The 7th entry of the same process should be rate limited.
57         assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
58     }
59 
60     @Test
testBufferClearing()61     public void testBufferClearing() throws Exception {
62         // The first 5 entries should not be rate limited.
63         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
64         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
65         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
66         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
67         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
68         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
69         // The 7th entry of the same process should be rate limited.
70         assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
71 
72         // After 11 minutes there should be nothing left in the buffer and the same type of entry
73         // should not get rate limited anymore.
74         mClock.setOffsetMillis(11 * 60 * 1000);
75 
76         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
77     }
78 
79     @Test
testRecentlyDroppedCount()80     public void testRecentlyDroppedCount() throws Exception {
81         assertEquals(0,
82                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
83         assertEquals(0,
84                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
85         assertEquals(0,
86                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
87         assertEquals(0,
88                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
89         assertEquals(0,
90                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
91         assertEquals(0,
92                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
93         assertEquals(1,
94                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
95         assertEquals(2,
96                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
97 
98         // After 11 minutes the rate limiting buffer will be cleared and rate limiting will stop.
99         mClock.setOffsetMillis(11 * 60 * 1000);
100 
101         // The first call after rate limiting stops will still return the number of dropped events.
102         assertEquals(2,
103                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
104         // The next call should show that the dropped event counter was reset.
105         assertEquals(0,
106                 mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
107     }
108 
109     @Test
testStrictRepeatedLimiting()110     public void testStrictRepeatedLimiting() throws Exception {
111         // The first 6 entries should not be rate limited.
112         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
113         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
114         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
115         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
116         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
117         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
118         // The 7th entry of the same process should be rate limited.
119         assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
120 
121         // After 11 minutes there should be nothing left in the buffer and the same type of entry
122         // should not get rate limited anymore.
123         mClock.setOffsetMillis(11 * 60 * 1000);
124         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
125         // The first 6 entries should not be rate limited again.
126         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
127         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
128         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
129         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
130         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
131 
132         // The 7th entry of the same process should be rate limited.
133         assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
134 
135         // After 11 more minutes there should be nothing left in the buffer and the same type of
136         // entry should not get rate limited anymore.
137         mClock.setOffsetMillis(22 * 60 * 1000);
138         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
139 
140         // Repeated crashes after the last reset being rate limited should be restricted faster.
141         assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
142 
143         // We now need to wait 21 minutes for the buffer should be empty again.
144         mClock.setOffsetMillis(43 * 60 * 1000);
145         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
146 
147         // After yet another 21 minutes, this time without triggering rate limiting, the strict
148         // limiting should be turnd off.
149         mClock.setOffsetMillis(64 * 60 * 1000);
150         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
151         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
152 
153         // As rate limiting was not triggered in the last reset, after another 11 minutes the
154         // buffer should still act as normal.
155         mClock.setOffsetMillis(75 * 60 * 1000);
156         // The first 6 entries should not be rate limited.
157         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
158         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
159         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
160         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
161         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
162         assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
163         // The 7th entry of the same process should be rate limited.
164         assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
165     }
166 
167     private static class TestClock implements DropboxRateLimiter.Clock {
168         long mOffsetMillis = 0L;
169 
uptimeMillis()170         public long uptimeMillis() {
171             return mOffsetMillis + SystemClock.uptimeMillis();
172         }
173 
setOffsetMillis(long millis)174         public void setOffsetMillis(long millis) {
175             mOffsetMillis = millis;
176         }
177     }
178 }
179