blob: adafda04d516298423086bcd5aa12a21d05d5b66 [file] [log] [blame]
Mike Mae45b9b12018-11-13 17:49:43 -08001/*
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 */
16package com.android.internal.os;
17
18import static org.junit.Assert.assertEquals;
19import static org.junit.Assert.assertTrue;
20
21import android.content.Context;
22import android.os.FileUtils;
23import android.support.test.InstrumentationRegistry;
24import android.support.test.filters.SmallTest;
25import android.support.test.runner.AndroidJUnit4;
26import android.util.SparseLongArray;
27
28import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
29
30import org.junit.After;
31import org.junit.Before;
32import org.junit.Test;
33import org.junit.runner.RunWith;
34
35import java.io.BufferedWriter;
36import java.io.File;
37import java.io.IOException;
38import java.nio.file.Files;
39import java.util.Random;
40
41/**
42 * Test class for {@link KernelCpuUidActiveTimeReader}.
43 *
44 * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidActiveTimeReaderTest
45 */
46@SmallTest
47@RunWith(AndroidJUnit4.class)
48public class KernelCpuUidActiveTimeReaderTest {
49 private File mTestDir;
50 private File mTestFile;
51 private KernelCpuUidActiveTimeReader mReader;
52 private VerifiableCallback mCallback;
53
54 private Random mRand = new Random(12345);
55 private final int mCpus = 4;
56 private final String mHeadline = "cpus: 4\n";
57 private final int[] mUids = {0, 1, 22, 333, 4444, 55555};
58
59 private Context getContext() {
60 return InstrumentationRegistry.getContext();
61 }
62
63 @Before
64 public void setUp() {
65 mTestDir = getContext().getDir("test", Context.MODE_PRIVATE);
66 mTestFile = new File(mTestDir, "test.file");
67 mReader = new KernelCpuUidActiveTimeReader(
68 new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false);
69 mCallback = new VerifiableCallback();
70 }
71
72 @After
73 public void tearDown() throws Exception {
74 FileUtils.deleteContents(mTestDir);
75 FileUtils.deleteContents(getContext().getFilesDir());
76 }
77
78 @Test
79 public void testReadDelta() throws Exception {
80 final long[][] times = increaseTime(new long[mUids.length][mCpus]);
81 writeToFile(mHeadline + uidLines(mUids, times));
82 mReader.readDelta(mCallback);
83 for (int i = 0; i < mUids.length; ++i) {
84 mCallback.verify(mUids[i], getActiveTime(times[i]));
85 }
86 mCallback.verifyNoMoreInteractions();
87
88 // Verify that a second call will only return deltas.
89 mCallback.clear();
90 final long[][] newTimes1 = increaseTime(times);
91 writeToFile(mHeadline + uidLines(mUids, newTimes1));
92 mReader.readDelta(mCallback);
93 for (int i = 0; i < mUids.length; ++i) {
94 mCallback.verify(mUids[i], getActiveTime(newTimes1[i]) - getActiveTime(times[i]));
95 }
96 mCallback.verifyNoMoreInteractions();
97
98 // Verify that there won't be a callback if the proc file values didn't change.
99 mCallback.clear();
100 mReader.readDelta(mCallback);
101 mCallback.verifyNoMoreInteractions();
102
103 // Verify that calling with a null callback doesn't result in any crashes
104 mCallback.clear();
105 final long[][] newTimes2 = increaseTime(newTimes1);
106 writeToFile(mHeadline + uidLines(mUids, newTimes2));
107 mReader.readDelta(null);
108 mCallback.verifyNoMoreInteractions();
109
110 // Verify that the readDelta call will only return deltas when
111 // the previous call had null callback.
112 mCallback.clear();
113 final long[][] newTimes3 = increaseTime(newTimes2);
114 writeToFile(mHeadline + uidLines(mUids, newTimes3));
115 mReader.readDelta(mCallback);
116 for (int i = 0; i < mUids.length; ++i) {
117 mCallback.verify(mUids[i], getActiveTime(newTimes3[i]) - getActiveTime(newTimes2[i]));
118 }
119 mCallback.verifyNoMoreInteractions();
120 assertTrue(mTestFile.delete());
121 }
122
123 @Test
124 public void testReadAbsolute() throws Exception {
125 final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
126 writeToFile(mHeadline + uidLines(mUids, times1));
127 mReader.readAbsolute(mCallback);
128 for (int i = 0; i < mUids.length; i++) {
129 mCallback.verify(mUids[i], getActiveTime(times1[i]));
130 }
131 mCallback.verifyNoMoreInteractions();
132
133 // Verify that a second call should still return absolute values
134 mCallback.clear();
135 final long[][] times2 = increaseTime(times1);
136 writeToFile(mHeadline + uidLines(mUids, times2));
137 mReader.readAbsolute(mCallback);
138 for (int i = 0; i < mUids.length; i++) {
139 mCallback.verify(mUids[i], getActiveTime(times2[i]));
140 }
141 mCallback.verifyNoMoreInteractions();
142 assertTrue(mTestFile.delete());
143 }
144
145 @Test
146 public void testReadDeltaDecreasedTime() throws Exception {
147 final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
148 writeToFile(mHeadline + uidLines(mUids, times1));
149 mReader.readDelta(mCallback);
150
151 // Verify that there should not be a callback for a particular UID if its time decreases.
152 mCallback.clear();
153 final long[][] times2 = increaseTime(times1);
154 System.arraycopy(times1[0], 0, times2[0], 0, mCpus);
155 times2[0][0] = 100;
156 writeToFile(mHeadline + uidLines(mUids, times2));
157 mReader.readDelta(mCallback);
158 for (int i = 1; i < mUids.length; i++) {
159 mCallback.verify(mUids[i], getActiveTime(times2[i]) - getActiveTime(times1[i]));
160 }
161 mCallback.verifyNoMoreInteractions();
162 assertTrue(mTestFile.delete());
163
164 // Verify that the internal state was not modified.
165 mCallback.clear();
166 final long[][] times3 = increaseTime(times2);
167 times3[0] = increaseTime(times1)[0];
168 writeToFile(mHeadline + uidLines(mUids, times3));
169 mReader.readDelta(mCallback);
170 mCallback.verify(mUids[0], getActiveTime(times3[0]) - getActiveTime(times1[0]));
171 for (int i = 1; i < mUids.length; i++) {
172 mCallback.verify(mUids[i], getActiveTime(times3[i]) - getActiveTime(times2[i]));
173 }
174 mCallback.verifyNoMoreInteractions();
175 }
176
177 @Test
178 public void testReadDeltaNegativeTime() throws Exception {
179 final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
180 writeToFile(mHeadline + uidLines(mUids, times1));
181 mReader.readDelta(mCallback);
182
183 // Verify that there should not be a callback for a particular UID if its time is -ve.
184 mCallback.clear();
185 final long[][] times2 = increaseTime(times1);
186 times2[0][0] *= -1;
187 writeToFile(mHeadline + uidLines(mUids, times2));
188 mReader.readDelta(mCallback);
189 for (int i = 1; i < mUids.length; i++) {
190 mCallback.verify(mUids[i], getActiveTime(times2[i]) - getActiveTime(times1[i]));
191 }
192 mCallback.verifyNoMoreInteractions();
193 assertTrue(mTestFile.delete());
194
195 // Verify that the internal state was not modified.
196 mCallback.clear();
197 final long[][] times3 = increaseTime(times2);
198 times3[0] = increaseTime(times1)[0];
199 writeToFile(mHeadline + uidLines(mUids, times3));
200 mReader.readDelta(mCallback);
201 mCallback.verify(mUids[0], getActiveTime(times3[0]) - getActiveTime(times1[0]));
202 for (int i = 1; i < mUids.length; i++) {
203 mCallback.verify(mUids[i], getActiveTime(times3[i]) - getActiveTime(times2[i]));
204 }
205 mCallback.verifyNoMoreInteractions();
206 }
207
208 private String uidLines(int[] uids, long[][] times) {
209 StringBuffer sb = new StringBuffer();
210 for (int i = 0; i < uids.length; i++) {
211 sb.append(uids[i]).append(':');
212 for (int j = 0; j < times[i].length; j++) {
213 sb.append(' ').append(times[i][j] / 10);
214 }
215 sb.append('\n');
216 }
217 return sb.toString();
218 }
219
220 private void writeToFile(String s) throws IOException {
221 try (BufferedWriter w = Files.newBufferedWriter(mTestFile.toPath())) {
222 w.write(s);
223 w.flush();
224 }
225 }
226
227 private long[][] increaseTime(long[][] original) {
228 long[][] newTime = new long[original.length][original[0].length];
229 for (int i = 0; i < original.length; i++) {
230 for (int j = 0; j < original[0].length; j++) {
231 newTime[i][j] = original[i][j] + mRand.nextInt(10000) * 1000 + 1000;
232 }
233 }
234 return newTime;
235 }
236
237 private long getActiveTime(long[] times) {
238 return times[0] + times[1] / 2 + times[2] / 3 + times[3] / 4;
239 }
240
241 private class VerifiableCallback implements KernelCpuUidTimeReader.Callback<Long> {
242 SparseLongArray mData = new SparseLongArray();
243
244 public void verify(int uid, long time) {
245 assertEquals(time, mData.get(uid));
246 mData.delete(uid);
247 }
248
249 public void clear() {
250 mData.clear();
251 }
252
253 @Override
254 public void onUidCpuTime(int uid, Long time) {
255 mData.put(uid, time);
256 }
257
258 public void verifyNoMoreInteractions() {
259 assertEquals(0, mData.size());
260 }
261 }
262}