blob: e375af3f7b0ef095da7a96a75d97dc9ae6c3decb [file] [log] [blame]
/*
* 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);
ArrayList<BinderCallsStats.ExportedCallStat> callStats = bcs.getExportedCallStats();
assertEquals(3, 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);
}
@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);
}
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;
}
}
}