blob: 07e2af8d4c66324eb8817e52d1d6da789245553a [file] [log] [blame]
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -07001/*
2 * Copyright (C) 2018 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.internal.os;
18
19import android.os.Binder;
20import android.platform.test.annotations.Presubmit;
21import android.support.test.filters.SmallTest;
22import android.support.test.runner.AndroidJUnit4;
Olivier Gaillardf82d2e732018-06-07 11:45:35 +010023import android.util.ArrayMap;
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070024import android.util.SparseArray;
25
26import org.junit.Assert;
27import org.junit.Test;
28import org.junit.runner.RunWith;
29
Olivier Gaillardf82d2e732018-06-07 11:45:35 +010030import java.io.PrintWriter;
31import java.io.StringWriter;
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070032import java.util.Arrays;
Olivier Gaillardf82d2e732018-06-07 11:45:35 +010033import java.util.HashMap;
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070034import java.util.List;
Olivier Gaillardf82d2e732018-06-07 11:45:35 +010035import java.util.Map;
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010036import java.util.Random;
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070037
38import static org.junit.Assert.assertEquals;
39
40@SmallTest
41@RunWith(AndroidJUnit4.class)
42@Presubmit
43public class BinderCallsStatsTest {
Olivier Gaillard58b56e32018-06-01 16:18:43 +010044 private static final int TEST_UID = 1;
45 private static final int REQUEST_SIZE = 2;
46 private static final int REPLY_SIZE = 3;
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070047
48 @Test
49 public void testDetailedOff() {
Olivier Gaillard1d7f6152018-07-03 13:57:58 +010050 TestBinderCallsStats bcs = new TestBinderCallsStats();
51 bcs.setDetailedTracking(false);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010052 bcs.setSamplingInterval(5);
Olivier Gaillard1d7f6152018-07-03 13:57:58 +010053
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070054 Binder binder = new Binder();
55 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
56 bcs.time += 10;
Olivier Gaillard58b56e32018-06-01 16:18:43 +010057 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070058
59 SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
60 assertEquals(1, uidEntries.size());
61 BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
62 Assert.assertNotNull(uidEntry);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010063 List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070064 assertEquals(1, uidEntry.callCount);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010065 assertEquals(1, uidEntry.recordedCallCount);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070066 assertEquals(10, uidEntry.cpuTimeMicros);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010067 assertEquals(binder.getClass().getName(), callStatsList.get(0).className);
68 assertEquals(1, callStatsList.get(0).msg);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070069
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010070 // CPU usage is sampled, should not be tracked here.
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070071 callSession = bcs.callStarted(binder, 1);
72 bcs.time += 20;
Olivier Gaillard58b56e32018-06-01 16:18:43 +010073 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070074 assertEquals(2, uidEntry.callCount);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010075 assertEquals(1, uidEntry.recordedCallCount);
76 assertEquals(10, uidEntry.cpuTimeMicros);
77 assertEquals(1, callStatsList.size());
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070078
79 callSession = bcs.callStarted(binder, 2);
80 bcs.time += 50;
Olivier Gaillard58b56e32018-06-01 16:18:43 +010081 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070082 uidEntry = bcs.getUidEntries().get(TEST_UID);
83 assertEquals(3, uidEntry.callCount);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +010084 assertEquals(1, uidEntry.recordedCallCount);
85 // Still sampled even for another API.
86 callStatsList = uidEntry.getCallStatsList();
87 assertEquals(2, callStatsList.size());
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070088 }
89
90 @Test
91 public void testDetailedOn() {
Olivier Gaillard1d7f6152018-07-03 13:57:58 +010092 TestBinderCallsStats bcs = new TestBinderCallsStats();
93 bcs.setDetailedTracking(true);
94
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070095 Binder binder = new Binder();
96 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
97 bcs.time += 10;
Olivier Gaillard58b56e32018-06-01 16:18:43 +010098 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -070099
100 SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
101 assertEquals(1, uidEntries.size());
102 BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
103 Assert.assertNotNull(uidEntry);
104 assertEquals(1, uidEntry.callCount);
105 assertEquals(10, uidEntry.cpuTimeMicros);
106 assertEquals(1, uidEntry.getCallStatsList().size());
107
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700108 List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
109 assertEquals(1, callStatsList.get(0).callCount);
110 assertEquals(10, callStatsList.get(0).cpuTimeMicros);
111 assertEquals(binder.getClass().getName(), callStatsList.get(0).className);
112 assertEquals(1, callStatsList.get(0).msg);
113
114 callSession = bcs.callStarted(binder, 1);
115 bcs.time += 20;
Olivier Gaillard58b56e32018-06-01 16:18:43 +0100116 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700117
118 uidEntry = bcs.getUidEntries().get(TEST_UID);
119 assertEquals(2, uidEntry.callCount);
120 assertEquals(30, uidEntry.cpuTimeMicros);
121 callStatsList = uidEntry.getCallStatsList();
122 assertEquals(1, callStatsList.size());
123
124 callSession = bcs.callStarted(binder, 2);
125 bcs.time += 50;
Olivier Gaillard58b56e32018-06-01 16:18:43 +0100126 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700127 uidEntry = bcs.getUidEntries().get(TEST_UID);
128 assertEquals(3, uidEntry.callCount);
129
130 // This is the first transaction of a new type, so the real CPU time will be measured
131 assertEquals(80, uidEntry.cpuTimeMicros);
132 callStatsList = uidEntry.getCallStatsList();
133 assertEquals(2, callStatsList.size());
134 }
135
136 @Test
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100137 public void testDisabled() {
138 TestBinderCallsStats bcs = new TestBinderCallsStats();
139 bcs.setEnabled(false);
140
141 Binder binder = new Binder();
142 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
143 bcs.time += 10;
144 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
145
146 SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
147 assertEquals(0, uidEntries.size());
148 }
149
150 @Test
151 public void testDisableInBetweenCall() {
152 TestBinderCallsStats bcs = new TestBinderCallsStats();
153 bcs.setEnabled(true);
154
155 Binder binder = new Binder();
156 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
157 bcs.time += 10;
158 bcs.setEnabled(false);
159 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
160
161 SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
162 assertEquals(0, uidEntries.size());
163 }
164
165 @Test
166 public void testEnableInBetweenCall() {
167 TestBinderCallsStats bcs = new TestBinderCallsStats();
168 bcs.setEnabled(false);
169
170 Binder binder = new Binder();
171 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
172 bcs.time += 10;
173 bcs.setEnabled(true);
174 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
175
176 SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
177 assertEquals(0, uidEntries.size());
178 }
179
180 @Test
181 public void testSampling() {
182 TestBinderCallsStats bcs = new TestBinderCallsStats();
183 bcs.setDetailedTracking(false);
184 bcs.setSamplingInterval(2);
185
186 Binder binder = new Binder();
187 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
188 bcs.time += 10;
189 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
190
191 callSession = bcs.callStarted(binder, 1);
192 bcs.time += 1000; // shoud be ignored.
193 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
194
195 callSession = bcs.callStarted(binder, 1);
196 bcs.time += 50;
197 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
198
199 SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
200 assertEquals(1, uidEntries.size());
201 BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
202 Assert.assertNotNull(uidEntry);
203 assertEquals(3, uidEntry.callCount);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +0100204 assertEquals(60 /* 10 + 50 */, uidEntry.cpuTimeMicros);
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100205
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +0100206 List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
207 assertEquals(1, callStatsList.size());
208 BinderCallsStats.CallStat callStats = callStatsList.get(0);
209 assertEquals(3, callStats.callCount);
210 assertEquals(2, callStats.recordedCallCount);
211 assertEquals(60, callStats.cpuTimeMicros);
212 assertEquals(50, callStats.maxCpuTimeMicros);
213 assertEquals(0, callStats.maxRequestSizeBytes);
214 assertEquals(0, callStats.maxReplySizeBytes);
215 }
216
217 @Test
218 public void testSamplingWithDifferentApis() {
219 TestBinderCallsStats bcs = new TestBinderCallsStats();
220 bcs.setDetailedTracking(false);
221 bcs.setSamplingInterval(2);
222
223 Binder binder = new Binder();
224 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
225 bcs.time += 10;
226 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
227
228 callSession = bcs.callStarted(binder, 2 /* another method */);
229 bcs.time += 1000; // shoud be ignored.
230 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
231
232
233 SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
234 assertEquals(1, uidEntries.size());
235 BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID);
236 assertEquals(2, uidEntry.callCount);
237 assertEquals(1, uidEntry.recordedCallCount);
238 assertEquals(10, uidEntry.cpuTimeMicros);
239
240 List<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList();
241 assertEquals(2, callStatsList.size());
242
243 BinderCallsStats.CallStat callStats = callStatsList.get(0);
244 assertEquals(1, callStats.callCount);
245 assertEquals(1, callStats.recordedCallCount);
246 assertEquals(10, callStats.cpuTimeMicros);
247 assertEquals(10, callStats.maxCpuTimeMicros);
248
249 // Only call count should is tracked, rest is sampled.
250 callStats = callStatsList.get(1);
251 assertEquals(1, callStats.callCount);
252 assertEquals(0, callStats.recordedCallCount);
253 assertEquals(0, callStats.cpuTimeMicros);
254 assertEquals(0, callStats.maxCpuTimeMicros);
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100255 }
256
257 @Test
Olivier Gaillard103aae22018-06-07 18:20:10 +0100258 public void testTransactionCodeResolved() {
259 TestBinderCallsStats bcs = new TestBinderCallsStats();
260 bcs.setDetailedTracking(true);
261 Binder binder = new Binder() {
262 @Override
263 public String getTransactionName(int code) {
264 return "resolved";
265 }
266 };
267 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
268 bcs.time += 10;
269 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
270
271 List<BinderCallsStats.CallStat> callStatsList =
272 bcs.getUidEntries().get(TEST_UID).getCallStatsList();
273 assertEquals(1, callStatsList.get(0).msg);
274 assertEquals("resolved", callStatsList.get(0).methodName);
275 }
276
277 @Test
Olivier Gaillard58b56e32018-06-01 16:18:43 +0100278 public void testParcelSize() {
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100279 TestBinderCallsStats bcs = new TestBinderCallsStats();
280 bcs.setDetailedTracking(true);
Olivier Gaillard58b56e32018-06-01 16:18:43 +0100281 Binder binder = new Binder();
282 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
283 bcs.time += 10;
284 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
285
286 List<BinderCallsStats.CallStat> callStatsList =
287 bcs.getUidEntries().get(TEST_UID).getCallStatsList();
288
289 assertEquals(REQUEST_SIZE, callStatsList.get(0).maxRequestSizeBytes);
290 assertEquals(REPLY_SIZE, callStatsList.get(0).maxReplySizeBytes);
291 }
292
293 @Test
Olivier Gaillard11965ed2018-06-04 14:14:04 +0100294 public void testMaxCpu() {
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100295 TestBinderCallsStats bcs = new TestBinderCallsStats();
296 bcs.setDetailedTracking(true);
Olivier Gaillard11965ed2018-06-04 14:14:04 +0100297 Binder binder = new Binder();
298 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
299 bcs.time += 50;
300 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
301
302 callSession = bcs.callStarted(binder, 1);
303 bcs.time += 10;
304 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
305
306 List<BinderCallsStats.CallStat> callStatsList =
307 bcs.getUidEntries().get(TEST_UID).getCallStatsList();
308
309 assertEquals(50, callStatsList.get(0).maxCpuTimeMicros);
310 }
311
312 @Test
313 public void testMaxLatency() {
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100314 TestBinderCallsStats bcs = new TestBinderCallsStats();
315 bcs.setDetailedTracking(true);
Olivier Gaillard11965ed2018-06-04 14:14:04 +0100316 Binder binder = new Binder();
317 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
318 bcs.elapsedTime += 5;
319 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
320
321 callSession = bcs.callStarted(binder, 1);
322 bcs.elapsedTime += 1;
323 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
324
325 List<BinderCallsStats.CallStat> callStatsList =
326 bcs.getUidEntries().get(TEST_UID).getCallStatsList();
327
328 assertEquals(5, callStatsList.get(0).maxLatencyMicros);
329 }
330
331 @Test
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700332 public void testGetHighestValues() {
333 List<Integer> list = Arrays.asList(1, 2, 3, 4);
334 List<Integer> highestValues = BinderCallsStats
335 .getHighestValues(list, value -> value, 0.8);
336 assertEquals(Arrays.asList(4, 3, 2), highestValues);
337 }
338
Olivier Gaillardf82d2e732018-06-07 11:45:35 +0100339 @Test
340 public void testExceptionCount() {
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100341 TestBinderCallsStats bcs = new TestBinderCallsStats();
342 bcs.setDetailedTracking(true);
Olivier Gaillardf82d2e732018-06-07 11:45:35 +0100343 Binder binder = new Binder();
344 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
345 bcs.callThrewException(callSession, new IllegalStateException());
346 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
347
348 callSession = bcs.callStarted(binder, 1);
349 bcs.callThrewException(callSession, new IllegalStateException());
350 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
351
352 callSession = bcs.callStarted(binder, 1);
353 bcs.callThrewException(callSession, new RuntimeException());
354 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
355
356 ArrayMap<String, Integer> expected = new ArrayMap<>();
357 expected.put("java.lang.IllegalStateException", 2);
358 expected.put("java.lang.RuntimeException", 1);
359 assertEquals(expected, bcs.getExceptionCounts());
360 }
361
362 @Test
363 public void testDumpDoesNotThrowException() {
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100364 TestBinderCallsStats bcs = new TestBinderCallsStats();
365 bcs.setDetailedTracking(true);
Olivier Gaillardf82d2e732018-06-07 11:45:35 +0100366 Binder binder = new Binder();
367 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
368 bcs.callThrewException(callSession, new IllegalStateException());
369 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
370
371 PrintWriter pw = new PrintWriter(new StringWriter());
372 bcs.dump(pw, new HashMap<>(), true);
373 }
374
Olivier Gaillard00bfb1b2018-07-10 11:25:09 +0100375 @Test
376 public void testGetExportedStatsWhenDetailedTrackingDisabled() {
377 TestBinderCallsStats bcs = new TestBinderCallsStats();
378 bcs.setDetailedTracking(false);
379 Binder binder = new Binder();
380 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
381 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
382
383 assertEquals(0, bcs.getExportedCallStats().size());
384 }
385
386 @Test
387 public void testGetExportedStatsWhenDetailedTrackingEnabled() {
388 TestBinderCallsStats bcs = new TestBinderCallsStats();
389 bcs.setDetailedTracking(true);
390 Binder binder = new Binder();
391 BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1);
392 bcs.time += 10;
393 bcs.elapsedTime += 20;
394 bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
395
396 assertEquals(1, bcs.getExportedCallStats().size());
397 BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0);
398 assertEquals(TEST_UID, stat.uid);
399 assertEquals("android.os.Binder", stat.className);
400 assertEquals("1", stat.methodName);
401 assertEquals(10, stat.cpuTimeMicros);
402 assertEquals(10, stat.maxCpuTimeMicros);
403 assertEquals(20, stat.latencyMicros);
404 assertEquals(20, stat.maxLatencyMicros);
405 assertEquals(1, stat.callCount);
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +0100406 assertEquals(1, stat.recordedCallCount);
Olivier Gaillard00bfb1b2018-07-10 11:25:09 +0100407 assertEquals(REQUEST_SIZE, stat.maxRequestSizeBytes);
408 assertEquals(REPLY_SIZE, stat.maxReplySizeBytes);
409 assertEquals(0, stat.exceptionCount);
410 }
411
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700412 static class TestBinderCallsStats extends BinderCallsStats {
413 int callingUid = TEST_UID;
414 long time = 1234;
Olivier Gaillard11965ed2018-06-04 14:14:04 +0100415 long elapsedTime = 0;
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700416
Olivier Gaillard1d7f6152018-07-03 13:57:58 +0100417 TestBinderCallsStats() {
Olivier Gaillard2c13c6f2018-07-16 16:55:58 +0100418 // Make random generator not random.
419 super(new Random() {
420 int mCallCount = 0;
421
422 public int nextInt() {
423 return mCallCount++;
424 }
425 });
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700426 }
427
428 @Override
429 protected long getThreadTimeMicro() {
430 return time;
431 }
432
433 @Override
Olivier Gaillard11965ed2018-06-04 14:14:04 +0100434 protected long getElapsedRealtimeMicro() {
435 return elapsedTime;
436 }
437
438 @Override
Fyodor Kupolovcf0fe2d2018-05-22 18:50:04 -0700439 protected int getCallingUid() {
440 return callingUid;
441 }
442 }
443
444}