1 /* 2 * Copyright (C) 2020 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.internal.os; 18 19 import android.os.Binder; 20 21 import com.android.internal.os.BinderCallHeavyHitterWatcher.HeavyHitterContainer; 22 23 import junit.framework.TestCase; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 import java.util.Random; 28 29 /** 30 * Tests for {@link BinderCallHeavyHitterWatcher}. 31 */ 32 public final class BinderHeavyHitterTest extends TestCase { 33 34 private boolean mListenerNotified = false; 35 36 private List<HeavyHitterContainer> mExpectedResult = null; 37 38 /** 39 * Generate random input. 40 */ generateRandomInput(final int total, final List<HeavyHitterContainer> heavyHitters, final List<Integer> numOfHeavyHits)41 private ArrayList<HeavyHitterContainer> generateRandomInput(final int total, 42 final List<HeavyHitterContainer> heavyHitters, 43 final List<Integer> numOfHeavyHits) { 44 final ArrayList<HeavyHitterContainer> result = new ArrayList<>(); 45 List<HeavyHitterContainer> flatternedHeavyHitters = null; 46 int totalHeavyHitters = 0; 47 if (numOfHeavyHits != null) { 48 flatternedHeavyHitters = new ArrayList<>(); 49 for (int i = numOfHeavyHits.size() - 1; i >= 0; i--) { 50 final int k = numOfHeavyHits.get(i); 51 totalHeavyHitters += k; 52 final HeavyHitterContainer container = heavyHitters.get(i); 53 for (int j = 0; j < k; j++) { 54 flatternedHeavyHitters.add(container); 55 } 56 } 57 } 58 int totalLightHitters = total - totalHeavyHitters; 59 final Binder[] binders = {new TestBinder1(), new TestBinder2(), new TestBinder3()}; 60 final int maxUid = 1000; 61 final int maxCode = 1000; 62 final Random rand = new Random(); 63 for (int i = 0; i < total; i++) { 64 HeavyHitterContainer container = null; 65 if (totalLightHitters <= 0) { 66 container = flatternedHeavyHitters.remove(rand.nextInt(totalHeavyHitters)); 67 totalHeavyHitters--; 68 } else if (totalHeavyHitters <= 0) { 69 container = newContainer(rand.nextInt(maxUid), 70 binders[rand.nextInt(binders.length)].getClass(), 71 rand.nextInt(maxCode), 0.0f); 72 totalLightHitters--; 73 } else { 74 int val = rand.nextInt(total - i); 75 if (val >= totalLightHitters) { 76 container = flatternedHeavyHitters.remove(rand.nextInt(totalHeavyHitters)); 77 totalHeavyHitters--; 78 } else { 79 container = newContainer(rand.nextInt(maxUid), 80 binders[rand.nextInt(binders.length)].getClass(), 81 rand.nextInt(maxCode), 0.0f); 82 totalLightHitters--; 83 } 84 } 85 result.add(container); 86 } 87 return result; 88 } 89 newContainer(final int uid, final Class clazz, final int code, final float freq)90 private HeavyHitterContainer newContainer(final int uid, final Class clazz, final int code, 91 final float freq) { 92 final HeavyHitterContainer container = new HeavyHitterContainer(); 93 container.mUid = uid; 94 container.mClass = clazz; 95 container.mCode = code; 96 container.mFrequency = freq; 97 return container; 98 } 99 onResult(final List<HeavyHitterContainer> results, final Integer inputSize, final Float threshod, final Long timeSpan)100 private void onResult(final List<HeavyHitterContainer> results, final Integer inputSize, 101 final Float threshod, final Long timeSpan) { 102 mListenerNotified = true; 103 if (mExpectedResult == null) { 104 assertTrue(results == null || results.size() == 0); 105 } else { 106 int size = mExpectedResult.size(); 107 assertEquals(size, results.size()); 108 for (int i = 0; i < size; i++) { 109 final HeavyHitterContainer container = mExpectedResult.get(i); 110 assertNotNull(container); 111 assertTrue(results.remove(container)); 112 } 113 assertEquals(0, results.size()); 114 } 115 } 116 testPositive()117 public void testPositive() throws Exception { 118 BinderCallHeavyHitterWatcher watcher = BinderCallHeavyHitterWatcher.getInstance(); 119 try { 120 List<HeavyHitterContainer> hitters = new ArrayList<>(); 121 List<Integer> counts = new ArrayList<>(); 122 hitters.add(newContainer(1001, TestBinder4.class, 1002, 0.4f)); 123 counts.add(400); 124 hitters.add(newContainer(2001, TestBinder5.class, 2002, 0.333f)); 125 counts.add(333); 126 ArrayList<HeavyHitterContainer> inputs = generateRandomInput(1000, hitters, counts); 127 inputs.addAll((List<HeavyHitterContainer>) inputs.clone()); 128 129 watcher.setConfig(true, inputs.size(), 0.333f, this::onResult); 130 mListenerNotified = false; 131 mExpectedResult = hitters; 132 133 for (int i = inputs.size() - 1; i >= 0; i--) { 134 final HeavyHitterContainer container = inputs.get(i); 135 watcher.onTransaction(container.mUid, container.mClass, container.mCode); 136 } 137 assertTrue(mListenerNotified); 138 } finally { 139 watcher.setConfig(false, 0, 0.0f, null); 140 mListenerNotified = false; 141 mExpectedResult = null; 142 } 143 } 144 testNegative()145 public void testNegative() throws Exception { 146 BinderCallHeavyHitterWatcher watcher = BinderCallHeavyHitterWatcher.getInstance(); 147 try { 148 List<HeavyHitterContainer> hitters = new ArrayList<>(); 149 List<Integer> counts = new ArrayList<>(); 150 hitters.add(newContainer(1001, TestBinder4.class, 1002, 0.332f)); 151 counts.add(332); 152 hitters.add(newContainer(2001, TestBinder5.class, 2002, 0.331f)); 153 counts.add(331); 154 ArrayList<HeavyHitterContainer> inputs = generateRandomInput(1000, hitters, counts); 155 inputs.addAll((List<HeavyHitterContainer>) inputs.clone()); 156 157 watcher.setConfig(true, inputs.size(), 0.333f, this::onResult); 158 mListenerNotified = false; 159 mExpectedResult = null; 160 161 for (int i = inputs.size() - 1; i >= 0; i--) { 162 final HeavyHitterContainer container = inputs.get(i); 163 watcher.onTransaction(container.mUid, container.mClass, container.mCode); 164 } 165 assertFalse(mListenerNotified); 166 } finally { 167 watcher.setConfig(false, 0, 0.0f, null); 168 mListenerNotified = false; 169 mExpectedResult = null; 170 } 171 } 172 173 private class TestBinder1 extends Binder { 174 } 175 176 private class TestBinder2 extends Binder { 177 } 178 179 private class TestBinder3 extends Binder { 180 } 181 182 private class TestBinder4 extends Binder { 183 } 184 185 private class TestBinder5 extends Binder { 186 } 187 } 188