| /* |
| * Copyright (C) 2018 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.internal.os; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertTrue; |
| |
| import android.os.Binder; |
| import android.os.SystemClock; |
| import android.platform.test.annotations.Presubmit; |
| import android.util.ArrayMap; |
| import android.util.SparseArray; |
| |
| import androidx.test.filters.SmallTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import com.android.internal.os.BinderInternal.CallSession; |
| |
| import org.junit.Assert; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Random; |
| |
| @SmallTest |
| @RunWith(AndroidJUnit4.class) |
| @Presubmit |
| public class BinderCallsStatsTest { |
| private static final int WORKSOURCE_UID = 1; |
| private static final int CALLING_UID = 2; |
| private static final int REQUEST_SIZE = 2; |
| private static final int REPLY_SIZE = 3; |
| private final CachedDeviceState mDeviceState = new CachedDeviceState(false, true); |
| |
| @Test |
| public void testDetailedOff() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(false); |
| bcs.setSamplingInterval(5); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, uidEntry.callCount); |
| assertEquals(1, uidEntry.recordedCallCount); |
| assertEquals(10, uidEntry.cpuTimeMicros); |
| assertEquals(binder.getClass(), callStatsList.get(0).binderClass); |
| assertEquals(1, callStatsList.get(0).transactionCode); |
| |
| // CPU usage is sampled, should not be tracked here. |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 20; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| assertEquals(2, uidEntry.callCount); |
| assertEquals(1, uidEntry.recordedCallCount); |
| assertEquals(10, uidEntry.cpuTimeMicros); |
| assertEquals(1, callStatsList.size()); |
| |
| callSession = bcs.callStarted(binder, 2, WORKSOURCE_UID); |
| bcs.time += 50; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); |
| assertEquals(3, uidEntry.callCount); |
| assertEquals(1, uidEntry.recordedCallCount); |
| // Still sampled even for another API. |
| callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| } |
| |
| @Test |
| public void testDetailedOn() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| assertEquals(1, uidEntry.callCount); |
| assertEquals(10, uidEntry.cpuTimeMicros); |
| assertEquals(1, new ArrayList(uidEntry.getCallStatsList()).size()); |
| |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.get(0).callCount); |
| assertEquals(10, callStatsList.get(0).cpuTimeMicros); |
| assertEquals(binder.getClass(), callStatsList.get(0).binderClass); |
| assertEquals(1, callStatsList.get(0).transactionCode); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 20; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); |
| assertEquals(2, uidEntry.callCount); |
| assertEquals(30, uidEntry.cpuTimeMicros); |
| callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| |
| callSession = bcs.callStarted(binder, 2, WORKSOURCE_UID); |
| bcs.time += 50; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); |
| assertEquals(3, uidEntry.callCount); |
| |
| // This is the first transaction of a new type, so the real CPU time will be measured |
| assertEquals(80, uidEntry.cpuTimeMicros); |
| callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(2, callStatsList.size()); |
| } |
| |
| @Test |
| public void testEnableInBetweenCall() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| Binder binder = new Binder(); |
| bcs.callEnded(null, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(0, uidEntries.size()); |
| } |
| |
| @Test |
| public void testInBetweenCallWhenExceptionThrown() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| Binder binder = new Binder(); |
| bcs.callThrewException(null, new IllegalStateException()); |
| bcs.callEnded(null, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(0, uidEntries.size()); |
| } |
| |
| @Test |
| public void testSampling() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(false); |
| bcs.setSamplingInterval(2); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 1000; // shoud be ignored. |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 50; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| assertEquals(3, uidEntry.callCount); |
| assertEquals(60 /* 10 + 50 */, uidEntry.cpuTimeMicros); |
| |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| BinderCallsStats.CallStat callStats = callStatsList.get(0); |
| assertEquals(3, callStats.callCount); |
| assertEquals(2, callStats.recordedCallCount); |
| assertEquals(60, callStats.cpuTimeMicros); |
| assertEquals(50, callStats.maxCpuTimeMicros); |
| assertEquals(0, callStats.maxRequestSizeBytes); |
| assertEquals(0, callStats.maxReplySizeBytes); |
| } |
| |
| @Test |
| public void testSamplingWithDifferentApis() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(false); |
| bcs.setSamplingInterval(2); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 2 /* another method */, WORKSOURCE_UID); |
| bcs.time += 1000; // shoud be ignored. |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| assertEquals(2, uidEntry.callCount); |
| assertEquals(1, uidEntry.recordedCallCount); |
| assertEquals(10, uidEntry.cpuTimeMicros); |
| |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| |
| BinderCallsStats.CallStat callStats = callStatsList.get(0); |
| assertEquals(1, callStats.callCount); |
| assertEquals(1, callStats.recordedCallCount); |
| assertEquals(10, callStats.cpuTimeMicros); |
| assertEquals(10, callStats.maxCpuTimeMicros); |
| } |
| |
| private static class BinderWithGetTransactionName extends Binder { |
| public static String getDefaultTransactionName(int code) { |
| return "resolved"; |
| } |
| } |
| |
| private static class AnotherBinderWithGetTransactionName extends Binder { |
| public static String getDefaultTransactionName(int code) { |
| return "foo" + code; |
| } |
| } |
| |
| @Test |
| public void testTransactionCodeResolved() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| Binder binder = new BinderWithGetTransactionName(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| List<BinderCallsStats.ExportedCallStat> callStatsList = |
| bcs.getExportedCallStats(); |
| assertEquals("resolved", callStatsList.get(0).methodName); |
| } |
| |
| @Test |
| public void testMultipleTransactionCodeResolved() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| |
| Binder binder = new AnotherBinderWithGetTransactionName(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| Binder binder2 = new BinderWithGetTransactionName(); |
| callSession = bcs.callStarted(binder2, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 2, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| List<BinderCallsStats.ExportedCallStat> callStatsList = |
| bcs.getExportedCallStats(); |
| assertEquals("foo1", callStatsList.get(0).methodName); |
| assertEquals(AnotherBinderWithGetTransactionName.class.getName(), |
| callStatsList.get(0).className); |
| assertEquals("foo2", callStatsList.get(1).methodName); |
| assertEquals(AnotherBinderWithGetTransactionName.class.getName(), |
| callStatsList.get(1).className); |
| assertEquals("resolved", callStatsList.get(2).methodName); |
| assertEquals(BinderWithGetTransactionName.class.getName(), |
| callStatsList.get(2).className); |
| } |
| |
| @Test |
| public void testResolvingCodeDoesNotThrowWhenMethodNotPresent() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| List<BinderCallsStats.ExportedCallStat> callStatsList = |
| bcs.getExportedCallStats(); |
| assertEquals("1", callStatsList.get(0).methodName); |
| } |
| |
| @Test |
| public void testParcelSize() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| List<BinderCallsStats.CallStat> callStatsList = |
| new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); |
| |
| assertEquals(REQUEST_SIZE, callStatsList.get(0).maxRequestSizeBytes); |
| assertEquals(REPLY_SIZE, callStatsList.get(0).maxReplySizeBytes); |
| } |
| |
| @Test |
| public void testMaxCpu() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 50; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| List<BinderCallsStats.CallStat> callStatsList = |
| new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); |
| |
| assertEquals(50, callStatsList.get(0).maxCpuTimeMicros); |
| } |
| |
| @Test |
| public void testMaxLatency() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.elapsedTime += 5; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.elapsedTime += 1; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| List<BinderCallsStats.CallStat> callStatsList = |
| new ArrayList(bcs.getUidEntries().get(WORKSOURCE_UID).getCallStatsList()); |
| |
| assertEquals(5, callStatsList.get(0).maxLatencyMicros); |
| } |
| |
| @Test |
| public void testGetHighestValues() { |
| List<Integer> list = Arrays.asList(1, 2, 3, 4); |
| List<Integer> highestValues = BinderCallsStats |
| .getHighestValues(list, value -> value, 0.8); |
| assertEquals(Arrays.asList(4, 3, 2), highestValues); |
| } |
| |
| @Test |
| public void testExceptionCount() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callThrewException(callSession, new IllegalStateException()); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callThrewException(callSession, new IllegalStateException()); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callThrewException(callSession, new RuntimeException()); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| ArrayMap<String, Integer> expected = new ArrayMap<>(); |
| expected.put("java.lang.IllegalStateException", 2); |
| expected.put("java.lang.RuntimeException", 1); |
| assertEquals(expected, bcs.getExceptionCounts()); |
| } |
| |
| @Test |
| public void testNoDataCollectedBeforeInitialDeviceStateSet() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(null); |
| bcs.setDetailedTracking(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| bcs.setDeviceState(mDeviceState.getReadonlyClient()); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(0, uidEntries.size()); |
| } |
| |
| @Test |
| public void testNoDataCollectedOnCharger() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| mDeviceState.setCharging(true); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| assertEquals(0, bcs.getUidEntries().size()); |
| } |
| |
| @Test |
| public void testScreenOff() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| mDeviceState.setScreenInteractive(false); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(false, callStatsList.get(0).screenInteractive); |
| } |
| |
| @Test |
| public void testScreenOn() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| mDeviceState.setScreenInteractive(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(true, callStatsList.get(0).screenInteractive); |
| } |
| |
| @Test |
| public void testOnCharger() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| mDeviceState.setCharging(true); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| assertEquals(0, bcs.getExportedCallStats().size()); |
| } |
| |
| @Test |
| public void testOnBattery() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| mDeviceState.setCharging(false); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| assertEquals(1, bcs.getExportedCallStats().size()); |
| } |
| |
| @Test |
| public void testDumpDoesNotThrowException() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callThrewException(callSession, new IllegalStateException()); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| PrintWriter pw = new PrintWriter(new StringWriter()); |
| bcs.dump(pw, new AppIdToPackageMap(new HashMap<>()), true); |
| } |
| |
| @Test |
| public void testGetExportedStatsWhenDetailedTrackingDisabled() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(false); |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| assertEquals(0, bcs.getExportedCallStats().size()); |
| } |
| |
| @Test |
| public void testGetExportedStatsWhenDetailedTrackingEnabled() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.elapsedTime += 20; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| assertEquals(1, bcs.getExportedCallStats().size()); |
| BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0); |
| assertEquals(WORKSOURCE_UID, stat.workSourceUid); |
| assertEquals(CALLING_UID, stat.callingUid); |
| assertEquals("android.os.Binder", stat.className); |
| assertEquals("1", stat.methodName); |
| assertEquals(true, stat.screenInteractive); |
| assertEquals(10, stat.cpuTimeMicros); |
| assertEquals(10, stat.maxCpuTimeMicros); |
| assertEquals(20, stat.latencyMicros); |
| assertEquals(20, stat.maxLatencyMicros); |
| assertEquals(1, stat.callCount); |
| assertEquals(1, stat.recordedCallCount); |
| assertEquals(REQUEST_SIZE, stat.maxRequestSizeBytes); |
| assertEquals(REPLY_SIZE, stat.maxReplySizeBytes); |
| assertEquals(0, stat.exceptionCount); |
| } |
| |
| @Test |
| public void testGetExportedStatsWithoutCalls() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| Binder binder = new Binder(); |
| assertEquals(0, bcs.getExportedCallStats().size()); |
| } |
| |
| @Test |
| public void testGetExportedExceptionsWithoutCalls() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| Binder binder = new Binder(); |
| assertEquals(0, bcs.getExceptionCounts().size()); |
| } |
| |
| @Test |
| public void testOverflow_sameEntry() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| bcs.setSamplingInterval(1); |
| bcs.setMaxBinderCallStats(2); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| BinderCallsStats.UidEntry uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| BinderCallsStats.CallStat callStats = callStatsList.get(0); |
| assertEquals(3, callStats.callCount); |
| } |
| |
| @Test |
| public void testOverflow_overflowEntry() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| bcs.setSamplingInterval(1); |
| bcs.setMaxBinderCallStats(1); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 2, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| // Should use the same overflow entry. |
| callSession = bcs.callStarted(binder, 3, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| List<BinderCallsStats.ExportedCallStat> callStatsList = bcs.getExportedCallStats(); |
| assertEquals(2, callStatsList.size()); |
| BinderCallsStats.ExportedCallStat callStats = callStatsList.get(0); |
| assertEquals(1, callStats.callCount); |
| assertEquals("1", callStats.methodName); |
| assertEquals("android.os.Binder", callStats.className); |
| assertEquals(CALLING_UID, callStats.callingUid); |
| |
| callStats = callStatsList.get(1); |
| assertEquals(2, callStats.callCount); |
| assertEquals("-1", callStats.methodName); |
| assertEquals("com.android.internal.os.BinderCallsStats$OverflowBinder", |
| callStats.className); |
| assertEquals(false , callStats.screenInteractive); |
| assertEquals(-1 , callStats.callingUid); |
| } |
| |
| @Test |
| public void testOverflow_oneOverflowEntryPerUid() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setDetailedTracking(true); |
| bcs.setSamplingInterval(1); |
| bcs.setMaxBinderCallStats(1); |
| |
| Binder binder = new Binder(); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| callSession = bcs.callStarted(binder, 2, WORKSOURCE_UID + 1); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID + 1); |
| |
| // Different uids have different overflow entries. |
| callSession = bcs.callStarted(binder, 2, WORKSOURCE_UID + 2); |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID + 2); |
| |
| List<BinderCallsStats.ExportedCallStat> callStatsList = bcs.getExportedCallStats(); |
| assertEquals(3, callStatsList.size()); |
| |
| BinderCallsStats.ExportedCallStat callStats = callStatsList.get(1); |
| assertEquals(WORKSOURCE_UID + 1, callStats.workSourceUid); |
| assertEquals(1, callStats.callCount); |
| assertEquals("com.android.internal.os.BinderCallsStats$OverflowBinder", |
| callStats.className); |
| |
| callStats = callStatsList.get(2); |
| assertEquals(WORKSOURCE_UID + 2, callStats.workSourceUid); |
| assertEquals(1, callStats.callCount); |
| assertEquals("com.android.internal.os.BinderCallsStats$OverflowBinder", |
| callStats.className); |
| } |
| |
| @Test |
| public void testAddsDebugEntries() { |
| long startTime = SystemClock.elapsedRealtime(); |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setAddDebugEntries(true); |
| bcs.setSamplingInterval(10); |
| ArrayList<BinderCallsStats.ExportedCallStat> callStats = bcs.getExportedCallStats(); |
| assertEquals(4, callStats.size()); |
| BinderCallsStats.ExportedCallStat debugEntry1 = callStats.get(0); |
| assertEquals("", debugEntry1.className); |
| assertEquals("__DEBUG_start_time_millis", debugEntry1.methodName); |
| assertTrue(startTime <= debugEntry1.latencyMicros); |
| BinderCallsStats.ExportedCallStat debugEntry2 = callStats.get(1); |
| assertEquals("", debugEntry2.className); |
| assertEquals("__DEBUG_end_time_millis", debugEntry2.methodName); |
| assertTrue(debugEntry1.latencyMicros <= debugEntry2.latencyMicros); |
| BinderCallsStats.ExportedCallStat debugEntry3 = callStats.get(2); |
| assertEquals("", debugEntry3.className); |
| assertEquals("__DEBUG_battery_time_millis", debugEntry3.methodName); |
| assertTrue(debugEntry3.latencyMicros >= 0); |
| BinderCallsStats.ExportedCallStat debugEntry4 = callStats.get(3); |
| assertEquals("__DEBUG_sampling_interval", debugEntry4.methodName); |
| assertEquals(10, debugEntry4.latencyMicros); |
| } |
| |
| @Test |
| public void testTrackScreenInteractiveDisabled() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setTrackScreenInteractive(false); |
| Binder binder = new Binder(); |
| |
| mDeviceState.setScreenInteractive(false); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| mDeviceState.setScreenInteractive(true); |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 1000; // shoud be ignored. |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| assertEquals(2, uidEntry.callCount); |
| |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| BinderCallsStats.CallStat callStats = callStatsList.get(0); |
| assertEquals(false, callStats.screenInteractive); |
| assertEquals(2, callStats.callCount); |
| assertEquals(2, callStats.recordedCallCount); |
| } |
| |
| @Test |
| public void testTrackCallingUidDisabled() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setTrackDirectCallerUid(false); |
| Binder binder = new Binder(); |
| |
| bcs.setCallingUid(1); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| bcs.setCallingUid(2); |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 1000; // shoud be ignored. |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| assertEquals(2, uidEntry.callCount); |
| |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| BinderCallsStats.CallStat callStats = callStatsList.get(0); |
| assertEquals(-1, callStats.callingUid); |
| assertEquals(2, callStats.callCount); |
| assertEquals(2, callStats.recordedCallCount); |
| } |
| |
| @Test |
| public void testTrackScreenInteractiveDisabled_sampling() { |
| TestBinderCallsStats bcs = new TestBinderCallsStats(); |
| bcs.setSamplingInterval(2); |
| bcs.setTrackScreenInteractive(false); |
| Binder binder = new Binder(); |
| |
| mDeviceState.setScreenInteractive(false); |
| CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 10; |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| mDeviceState.setScreenInteractive(true); |
| callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); |
| bcs.time += 1000; // shoud be ignored. |
| bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); |
| |
| SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); |
| assertEquals(1, uidEntries.size()); |
| BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID); |
| Assert.assertNotNull(uidEntry); |
| assertEquals(2, uidEntry.callCount); |
| |
| List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList()); |
| assertEquals(1, callStatsList.size()); |
| BinderCallsStats.CallStat callStats = callStatsList.get(0); |
| assertEquals(false, callStats.screenInteractive); |
| assertEquals(2, callStats.callCount); |
| assertEquals(1, callStats.recordedCallCount); |
| } |
| |
| class TestBinderCallsStats extends BinderCallsStats { |
| public int callingUid = CALLING_UID; |
| public long time = 1234; |
| public long elapsedTime = 0; |
| |
| TestBinderCallsStats() { |
| this(mDeviceState); |
| } |
| |
| TestBinderCallsStats(CachedDeviceState deviceState) { |
| // Make random generator not random. |
| super(new Injector() { |
| public Random getRandomGenerator() { |
| return new Random() { |
| int mCallCount = 0; |
| |
| public int nextInt() { |
| return mCallCount++; |
| } |
| }; |
| } |
| }); |
| setSamplingInterval(1); |
| setAddDebugEntries(false); |
| setTrackScreenInteractive(true); |
| setTrackDirectCallerUid(true); |
| if (deviceState != null) { |
| setDeviceState(deviceState.getReadonlyClient()); |
| } |
| } |
| |
| @Override |
| protected long getThreadTimeMicro() { |
| return time; |
| } |
| |
| @Override |
| protected long getElapsedRealtimeMicro() { |
| return elapsedTime; |
| } |
| |
| @Override |
| protected int getCallingUid() { |
| return callingUid; |
| } |
| |
| protected void setCallingUid(int uid) { |
| callingUid = uid; |
| } |
| } |
| |
| } |