blob: 0b9fa488b9653a5b12e58bda5404bd99847d1af7 [file] [log] [blame]
Enrico Granata517a1e02017-09-20 16:15:50 -07001/*
2 * Copyright (C) 2017 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.car;
18
Pavel Maltseved2c8642017-12-18 12:56:26 -080019import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNotNull;
22import static org.junit.Assert.assertNull;
23import static org.junit.Assert.assertTrue;
24import static org.junit.Assert.fail;
25
Enrico Granata286cd8e2017-09-25 14:46:49 -070026import android.annotation.NonNull;
27import android.annotation.Nullable;
Enrico Granata517a1e02017-09-20 16:15:50 -070028import android.car.Car;
29import android.car.storagemonitoring.CarStorageMonitoringManager;
Enrico Granatadbda56f2017-12-18 11:53:22 -080030import android.car.storagemonitoring.IoStatsEntry;
31import android.car.storagemonitoring.IoStats;
Enrico Granata1690a622018-01-22 17:34:46 -080032import android.car.storagemonitoring.LifetimeWriteInfo;
Enrico Granata7e0150d2017-11-06 17:20:17 -080033import android.car.storagemonitoring.UidIoRecord;
Enrico Granata1172f882017-09-21 14:51:30 -070034import android.car.storagemonitoring.WearEstimate;
Enrico Granata286cd8e2017-09-25 14:46:49 -070035import android.car.storagemonitoring.WearEstimateChange;
Enrico Granata43024de2017-11-16 17:09:37 -080036import android.content.Intent;
Enrico Granata7dce3792017-11-09 14:13:28 -080037import android.os.SystemClock;
Pavel Maltseved2c8642017-12-18 12:56:26 -080038import android.support.test.filters.MediumTest;
39import android.support.test.runner.AndroidJUnit4;
Enrico Granata286cd8e2017-09-25 14:46:49 -070040import android.util.JsonWriter;
41import android.util.Log;
Enrico Granatab19bc322017-10-12 12:25:06 -070042import android.util.Pair;
Enrico Granataa97fce22017-10-27 14:57:34 -070043import android.util.SparseArray;
Pavel Maltseved2c8642017-12-18 12:56:26 -080044
Enrico Granata1690a622018-01-22 17:34:46 -080045import com.android.car.storagemonitoring.LifetimeWriteInfoProvider;
Enrico Granataa97fce22017-10-27 14:57:34 -070046import com.android.car.storagemonitoring.UidIoStatsProvider;
Enrico Granata286cd8e2017-09-25 14:46:49 -070047import com.android.car.storagemonitoring.WearEstimateRecord;
48import com.android.car.storagemonitoring.WearHistory;
Enrico Granata517a1e02017-09-20 16:15:50 -070049import com.android.car.storagemonitoring.WearInformation;
Enrico Granatab19bc322017-10-12 12:25:06 -070050import com.android.car.storagemonitoring.WearInformationProvider;
51import com.android.car.systeminterface.StorageMonitoringInterface;
52import com.android.car.systeminterface.SystemInterface;
53import com.android.car.systeminterface.SystemStateInterface;
54import com.android.car.systeminterface.TimeInterface;
Pavel Maltseved2c8642017-12-18 12:56:26 -080055
Enrico Granata1690a622018-01-22 17:34:46 -080056import com.android.car.test.utils.TemporaryFile;
57import java.util.Collection;
58import org.json.JSONArray;
59import org.json.JSONObject;
Pavel Maltseved2c8642017-12-18 12:56:26 -080060import org.junit.Rule;
61import org.junit.Test;
62import org.junit.rules.TestName;
63import org.junit.runner.RunWith;
64
Enrico Granata286cd8e2017-09-25 14:46:49 -070065import java.io.File;
66import java.io.FileWriter;
67import java.io.IOException;
Enrico Granatab19bc322017-10-12 12:25:06 -070068import java.time.Duration;
Enrico Granata286cd8e2017-09-25 14:46:49 -070069import java.time.Instant;
Enrico Granatab19bc322017-10-12 12:25:06 -070070import java.util.ArrayList;
Enrico Granataa97fce22017-10-27 14:57:34 -070071import java.util.Arrays;
Enrico Granatab19bc322017-10-12 12:25:06 -070072import java.util.Comparator;
Enrico Granata286cd8e2017-09-25 14:46:49 -070073import java.util.HashMap;
74import java.util.List;
75import java.util.Map;
Enrico Granata517a1e02017-09-20 16:15:50 -070076
77/** Test the public entry points for the CarStorageMonitoringManager */
Pavel Maltseved2c8642017-12-18 12:56:26 -080078@RunWith(AndroidJUnit4.class)
Enrico Granata517a1e02017-09-20 16:15:50 -070079@MediumTest
80public class CarStorageMonitoringTest extends MockedCarTestBase {
81 private static final String TAG = CarStorageMonitoringTest.class.getSimpleName();
82
Pavel Maltseved2c8642017-12-18 12:56:26 -080083 @Rule public TestName mTestName = new TestName();
84
Enrico Granata1172f882017-09-21 14:51:30 -070085 private static final WearInformation DEFAULT_WEAR_INFORMATION =
Enrico Granata286cd8e2017-09-25 14:46:49 -070086 new WearInformation(30, 0, WearInformation.PRE_EOL_INFO_NORMAL);
87
Enrico Granata43024de2017-11-16 17:09:37 -080088 static class ResourceOverrides {
89 private final HashMap<Integer, Integer> mIntegerOverrides = new HashMap<>();
90 private final HashMap<Integer, String> mStringOverrides = new HashMap<>();
91
92 void override(int id, int value) {
93 mIntegerOverrides.put(id, value);
94 }
95 void override(int id, String value) {
96 mStringOverrides.put(id, value);
97 }
98
99 void overrideResources(MockResources resources) {
100 mIntegerOverrides.forEach(resources::overrideResource);
101 mStringOverrides.forEach(resources::overrideResource);
102 }
103 }
104
Pavel Maltseved2c8642017-12-18 12:56:26 -0800105 private final Map<String, ResourceOverrides> PER_TEST_RESOURCES =
Enrico Granata43024de2017-11-16 17:09:37 -0800106 new HashMap<String, ResourceOverrides>() {
107 {
108 put("testIntentOnExcessiveWrite",
109 new ResourceOverrides() {{
110 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
111 override(R.integer.acceptableWrittenKBytesPerSample, 10);
112 override(R.integer.acceptableFsyncCallsPerSample, 1000);
113 override(R.string.intentReceiverForUnacceptableIoMetrics,
Pavel Maltseved2c8642017-12-18 12:56:26 -0800114 getFlattenComponent(
115 CarStorageMonitoringBroadcastReceiver.class));
Enrico Granata43024de2017-11-16 17:09:37 -0800116 }});
117
118 put("testIntentOnExcessiveFsync",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800119 new ResourceOverrides() {{
120 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
121 override(R.integer.acceptableWrittenKBytesPerSample, 1000);
122 override(R.integer.acceptableFsyncCallsPerSample, 2);
123 override(R.string.intentReceiverForUnacceptableIoMetrics,
124 getFlattenComponent(
125 CarStorageMonitoringBroadcastReceiver.class));
126 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800127
128 put("testZeroWindowDisablesCollection",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800129 new ResourceOverrides() {{
130 override(R.integer.ioStatsNumSamplesToStore, 0);
131 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800132
Enrico Granata43024de2017-11-16 17:09:37 -0800133 }
134 };
135
Enrico Granataa97fce22017-10-27 14:57:34 -0700136 private static final class TestData {
137 static final TestData DEFAULT = new TestData(0, DEFAULT_WEAR_INFORMATION, null, null);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700138
139 final long uptime;
140 @NonNull
141 final WearInformation wearInformation;
142 @Nullable
143 final WearHistory wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700144 @NonNull
Enrico Granata7e0150d2017-11-06 17:20:17 -0800145 final UidIoRecord[] ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800146 @NonNull
147 final LifetimeWriteInfo[] previousLifetimeWriteInfo;
148 @NonNull
149 final LifetimeWriteInfo[] currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700150
Enrico Granata43024de2017-11-16 17:09:37 -0800151
Enrico Granataa97fce22017-10-27 14:57:34 -0700152 TestData(long uptime,
Enrico Granata1690a622018-01-22 17:34:46 -0800153 @Nullable WearInformation wearInformation,
154 @Nullable WearHistory wearHistory,
155 @Nullable UidIoRecord[] ioStats) {
156 this(uptime, wearInformation, wearHistory, ioStats, null, null);
157 }
158
159 TestData(long uptime,
Enrico Granataa97fce22017-10-27 14:57:34 -0700160 @Nullable WearInformation wearInformation,
161 @Nullable WearHistory wearHistory,
Enrico Granata1690a622018-01-22 17:34:46 -0800162 @Nullable UidIoRecord[] ioStats,
163 @Nullable LifetimeWriteInfo[] previousLifetimeWriteInfo,
164 @Nullable LifetimeWriteInfo[] currentLifetimeWriteInfo) {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700165 if (wearInformation == null) wearInformation = DEFAULT_WEAR_INFORMATION;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800166 if (ioStats == null) ioStats = new UidIoRecord[0];
Enrico Granata1690a622018-01-22 17:34:46 -0800167 if (previousLifetimeWriteInfo == null) {
168 previousLifetimeWriteInfo = new LifetimeWriteInfo[0];
169 }
170 if (currentLifetimeWriteInfo == null) {
171 currentLifetimeWriteInfo = new LifetimeWriteInfo[0];
172 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700173 this.uptime = uptime;
174 this.wearInformation = wearInformation;
175 this.wearHistory = wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700176 this.ioStats = ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800177 this.previousLifetimeWriteInfo = previousLifetimeWriteInfo;
178 this.currentLifetimeWriteInfo = currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700179 }
180 }
181
Enrico Granataa97fce22017-10-27 14:57:34 -0700182 private static final Map<String, TestData> PER_TEST_DATA =
Enrico Granata7e0150d2017-11-06 17:20:17 -0800183 new HashMap<String, TestData>() {
184 {
185 put("testReadWearHistory",
186 new TestData(6500, DEFAULT_WEAR_INFORMATION,
187 WearHistory.fromRecords(
188 WearEstimateRecord.Builder.newBuilder()
189 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
190 .toWearEstimate(new WearEstimate(10, 0))
191 .atUptime(1000)
192 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
193 WearEstimateRecord.Builder.newBuilder()
194 .fromWearEstimate(new WearEstimate(10, 0))
195 .toWearEstimate(new WearEstimate(20, 0))
196 .atUptime(4000)
197 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
198 WearEstimateRecord.Builder.newBuilder()
199 .fromWearEstimate(new WearEstimate(20, 0))
200 .toWearEstimate(new WearEstimate(30, 0))
201 .atUptime(6500)
202 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700203
Enrico Granata7e0150d2017-11-06 17:20:17 -0800204 put("testNotAcceptableWearEvent",
205 new TestData(2520006499L,
206 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
207 WearHistory.fromRecords(
208 WearEstimateRecord.Builder.newBuilder()
209 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
210 .toWearEstimate(new WearEstimate(10, 0))
211 .atUptime(1000)
212 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
213 WearEstimateRecord.Builder.newBuilder()
214 .fromWearEstimate(new WearEstimate(10, 0))
215 .toWearEstimate(new WearEstimate(20, 0))
216 .atUptime(4000)
217 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
218 WearEstimateRecord.Builder.newBuilder()
219 .fromWearEstimate(new WearEstimate(20, 0))
220 .toWearEstimate(new WearEstimate(30, 0))
221 .atUptime(6500)
222 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700223
Enrico Granata7e0150d2017-11-06 17:20:17 -0800224 put("testAcceptableWearEvent",
225 new TestData(2520006501L,
226 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
227 WearHistory.fromRecords(
228 WearEstimateRecord.Builder.newBuilder()
229 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
230 .toWearEstimate(new WearEstimate(10, 0))
231 .atUptime(1000)
232 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
233 WearEstimateRecord.Builder.newBuilder()
234 .fromWearEstimate(new WearEstimate(10, 0))
235 .toWearEstimate(new WearEstimate(20, 0))
236 .atUptime(4000)
237 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
238 WearEstimateRecord.Builder.newBuilder()
239 .fromWearEstimate(new WearEstimate(20, 0))
240 .toWearEstimate(new WearEstimate(30, 0))
241 .atUptime(6500)
242 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granataa97fce22017-10-27 14:57:34 -0700243
Enrico Granata7e0150d2017-11-06 17:20:17 -0800244 put("testBootIoStats",
245 new TestData(1000L,
246 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
247 null,
248 new UidIoRecord[]{
249 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
250 0, 0, 0, 0, 0),
251 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
252 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700253
Enrico Granata7e0150d2017-11-06 17:20:17 -0800254 put("testAggregateIoStats",
255 new TestData(1000L,
256 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
257 null,
258 new UidIoRecord[]{
259 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
260 0, 0, 0, 0, 0),
261 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
262 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700263
Enrico Granata7e0150d2017-11-06 17:20:17 -0800264 put("testIoStatsDeltas",
265 new TestData(1000L,
266 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
267 null,
268 new UidIoRecord[]{
269 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
270 0, 0, 0, 0, 0)}));
Enrico Granata1690a622018-01-22 17:34:46 -0800271
272 put("testComputeShutdownCost",
273 new TestData(1000L,
274 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
275 null,
276 null,
277 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
278 new LifetimeWriteInfo("p2", "ext4", 100),
279 new LifetimeWriteInfo("p3", "f2fs", 100)},
280 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
281 new LifetimeWriteInfo("p2", "ext4", 300),
282 new LifetimeWriteInfo("p3", "f2fs", 100)}));
283
284 put("testNegativeShutdownCost",
285 new TestData(1000L,
286 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
287 null,
288 null,
289 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
290 new LifetimeWriteInfo("p2", "ext4", 100),
291 new LifetimeWriteInfo("p3", "f2fs", 200)},
292 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
293 new LifetimeWriteInfo("p2", "ext4", 300),
294 new LifetimeWriteInfo("p3", "f2fs", 100)}));
Enrico Granata7e0150d2017-11-06 17:20:17 -0800295 }};
Enrico Granata1172f882017-09-21 14:51:30 -0700296
Enrico Granatab19bc322017-10-12 12:25:06 -0700297 private final MockSystemStateInterface mMockSystemStateInterface =
298 new MockSystemStateInterface();
299 private final MockStorageMonitoringInterface mMockStorageMonitoringInterface =
300 new MockStorageMonitoringInterface();
Enrico Granata0f72b742017-11-02 18:26:41 -0700301 private final MockTimeInterface mMockTimeInterface =
302 new MockTimeInterface();
Enrico Granatab19bc322017-10-12 12:25:06 -0700303
Enrico Granata517a1e02017-09-20 16:15:50 -0700304 private CarStorageMonitoringManager mCarStorageMonitoringManager;
305
306 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700307 protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() {
308 SystemInterface.Builder builder = super.getSystemInterfaceBuilder();
309 return builder.withSystemStateInterface(mMockSystemStateInterface)
310 .withStorageMonitoringInterface(mMockStorageMonitoringInterface)
Enrico Granata0f72b742017-11-02 18:26:41 -0700311 .withTimeInterface(mMockTimeInterface);
Enrico Granatab19bc322017-10-12 12:25:06 -0700312 }
313
314 @Override
Enrico Granata517a1e02017-09-20 16:15:50 -0700315 protected synchronized void configureFakeSystemInterface() {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700316 try {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800317 final TestData wearData = PER_TEST_DATA.getOrDefault(getName(), TestData.DEFAULT);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700318 final WearHistory wearHistory = wearData.wearHistory;
319
Enrico Granatab19bc322017-10-12 12:25:06 -0700320 mMockStorageMonitoringInterface.setWearInformation(wearData.wearInformation);
Enrico Granata1690a622018-01-22 17:34:46 -0800321 mMockStorageMonitoringInterface.setWriteInfo(wearData.currentLifetimeWriteInfo);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700322
323 if (wearHistory != null) {
324 File wearHistoryFile = new File(getFakeSystemInterface().getFilesDir(),
325 CarStorageMonitoringService.WEAR_INFO_FILENAME);
326 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(wearHistoryFile))) {
327 wearHistory.writeToJson(jsonWriter);
328 }
329 }
330
331 if (wearData.uptime > 0) {
332 File uptimeFile = new File(getFakeSystemInterface().getFilesDir(),
Enrico Granatab19bc322017-10-12 12:25:06 -0700333 CarStorageMonitoringService.UPTIME_TRACKER_FILENAME);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700334 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(uptimeFile))) {
335 jsonWriter.beginObject();
336 jsonWriter.name("uptime").value(wearData.uptime);
337 jsonWriter.endObject();
338 }
339 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700340
Enrico Granata1690a622018-01-22 17:34:46 -0800341 if (wearData.previousLifetimeWriteInfo.length > 0) {
342 File previousLifetimeFile = new File(getFakeSystemInterface().getFilesDir(),
343 CarStorageMonitoringService.LIFETIME_WRITES_FILENAME);
344 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(previousLifetimeFile))) {
345 jsonWriter.beginObject();
346 jsonWriter.name("lifetimeWriteInfo").beginArray();
347 for (LifetimeWriteInfo writeInfo : wearData.previousLifetimeWriteInfo) {
348 writeInfo.writeToJson(jsonWriter);
349 }
350 jsonWriter.endArray().endObject();
351 }
352 }
353
Enrico Granataa97fce22017-10-27 14:57:34 -0700354 Arrays.stream(wearData.ioStats).forEach(
355 mMockStorageMonitoringInterface::addIoStatsRecord);
356
Enrico Granata286cd8e2017-09-25 14:46:49 -0700357 } catch (IOException e) {
358 Log.e(TAG, "failed to configure fake system interface", e);
359 fail("failed to configure fake system interface instance");
360 }
Enrico Granata43024de2017-11-16 17:09:37 -0800361 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700362
Enrico Granata43024de2017-11-16 17:09:37 -0800363 @Override
364 protected synchronized void configureResourceOverrides(MockResources resources) {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800365 final ResourceOverrides overrides = PER_TEST_RESOURCES.getOrDefault(getName(), null);
Enrico Granata43024de2017-11-16 17:09:37 -0800366 if (overrides != null) {
367 overrides.overrideResources(resources);
368 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700369 }
370
371 @Override
Pavel Maltseved2c8642017-12-18 12:56:26 -0800372 public void setUp() throws Exception {
Enrico Granata517a1e02017-09-20 16:15:50 -0700373 super.setUp();
Enrico Granatab19bc322017-10-12 12:25:06 -0700374 mMockSystemStateInterface.executeBootCompletedActions();
Enrico Granatacf53fd72017-09-28 10:45:44 -0700375
Enrico Granata517a1e02017-09-20 16:15:50 -0700376 mCarStorageMonitoringManager =
377 (CarStorageMonitoringManager) getCar().getCarManager(Car.STORAGE_MONITORING_SERVICE);
378 }
379
Pavel Maltseved2c8642017-12-18 12:56:26 -0800380 @Test
Enrico Granata517a1e02017-09-20 16:15:50 -0700381 public void testReadPreEolInformation() throws Exception {
Enrico Granata1172f882017-09-21 14:51:30 -0700382 assertEquals(DEFAULT_WEAR_INFORMATION.preEolInfo,
Enrico Granata517a1e02017-09-20 16:15:50 -0700383 mCarStorageMonitoringManager.getPreEolIndicatorStatus());
384 }
Enrico Granata1172f882017-09-21 14:51:30 -0700385
Pavel Maltseved2c8642017-12-18 12:56:26 -0800386 @Test
Enrico Granata1172f882017-09-21 14:51:30 -0700387 public void testReadWearEstimate() throws Exception {
388 final WearEstimate wearEstimate = mCarStorageMonitoringManager.getWearEstimate();
389
390 assertNotNull(wearEstimate);
391 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateA, wearEstimate.typeA);
392 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateB, wearEstimate.typeB);
393 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700394
Pavel Maltseved2c8642017-12-18 12:56:26 -0800395 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700396 public void testReadWearHistory() throws Exception {
397 final List<WearEstimateChange> wearEstimateChanges =
398 mCarStorageMonitoringManager.getWearEstimateHistory();
399
400 assertNotNull(wearEstimateChanges);
401 assertFalse(wearEstimateChanges.isEmpty());
402
Enrico Granataa97fce22017-10-27 14:57:34 -0700403 final WearHistory expectedWearHistory = PER_TEST_DATA.get(getName()).wearHistory;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700404
405 assertEquals(expectedWearHistory.size(), wearEstimateChanges.size());
406 for (int i = 0; i < wearEstimateChanges.size(); ++i) {
407 final WearEstimateRecord expected = expectedWearHistory.get(i);
408 final WearEstimateChange actual = wearEstimateChanges.get(i);
409
410 assertTrue(expected.isSameAs(actual));
411 }
412 }
413
414 private void checkLastWearEvent(boolean isAcceptable) throws Exception {
415 final List<WearEstimateChange> wearEstimateChanges =
416 mCarStorageMonitoringManager.getWearEstimateHistory();
417
418 assertNotNull(wearEstimateChanges);
419 assertFalse(wearEstimateChanges.isEmpty());
420
Enrico Granataa97fce22017-10-27 14:57:34 -0700421 final TestData wearData = PER_TEST_DATA.get(getName());
Enrico Granata286cd8e2017-09-25 14:46:49 -0700422
423 final WearInformation expectedCurrentWear = wearData.wearInformation;
424 final WearEstimate expectedPreviousWear = wearData.wearHistory.getLast().getNewWearEstimate();
425
426 final WearEstimateChange actualCurrentWear =
427 wearEstimateChanges.get(wearEstimateChanges.size() - 1);
428
429 assertEquals(isAcceptable, actualCurrentWear.isAcceptableDegradation);
430 assertEquals(expectedCurrentWear.toWearEstimate(), actualCurrentWear.newEstimate);
431 assertEquals(expectedPreviousWear, actualCurrentWear.oldEstimate);
432 }
433
Pavel Maltseved2c8642017-12-18 12:56:26 -0800434 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700435 public void testNotAcceptableWearEvent() throws Exception {
436 checkLastWearEvent(false);
437 }
438
Pavel Maltseved2c8642017-12-18 12:56:26 -0800439 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700440 public void testAcceptableWearEvent() throws Exception {
441 checkLastWearEvent(true);
442 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700443
Pavel Maltseved2c8642017-12-18 12:56:26 -0800444 @Test
Enrico Granataa97fce22017-10-27 14:57:34 -0700445 public void testBootIoStats() throws Exception {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800446 final List<IoStatsEntry> bootIoStats =
Enrico Granataa97fce22017-10-27 14:57:34 -0700447 mCarStorageMonitoringManager.getBootIoStats();
448
449 assertNotNull(bootIoStats);
450 assertFalse(bootIoStats.isEmpty());
451
Enrico Granata7e0150d2017-11-06 17:20:17 -0800452 final UidIoRecord[] bootIoRecords = PER_TEST_DATA.get(getName()).ioStats;
Enrico Granataa97fce22017-10-27 14:57:34 -0700453
454 bootIoStats.forEach(uidIoStats -> assertTrue(Arrays.stream(bootIoRecords).anyMatch(
455 ioRecord -> uidIoStats.representsSameMetrics(ioRecord))));
456 }
457
Pavel Maltseved2c8642017-12-18 12:56:26 -0800458 @Test
Enrico Granata0f72b742017-11-02 18:26:41 -0700459 public void testAggregateIoStats() throws Exception {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800460 UidIoRecord oldRecord1000 = mMockStorageMonitoringInterface.getIoStatsRecord(1000);
Enrico Granata0f72b742017-11-02 18:26:41 -0700461
Enrico Granata7e0150d2017-11-06 17:20:17 -0800462 UidIoRecord newRecord1000 = new UidIoRecord(1000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700463 oldRecord1000.foreground_rchar,
464 oldRecord1000.foreground_wchar + 50,
465 oldRecord1000.foreground_read_bytes,
466 oldRecord1000.foreground_write_bytes + 100,
467 oldRecord1000.foreground_fsync + 1,
468 oldRecord1000.background_rchar,
469 oldRecord1000.background_wchar,
470 oldRecord1000.background_read_bytes,
471 oldRecord1000.background_write_bytes,
472 oldRecord1000.background_fsync);
473
474 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord1000);
475
Enrico Granata7e0150d2017-11-06 17:20:17 -0800476 UidIoRecord record2000 = new UidIoRecord(2000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700477 1024,
478 2048,
479 0,
480 1024,
481 1,
482 0,
483 0,
484 0,
485 0,
486 0);
487
488 mMockStorageMonitoringInterface.addIoStatsRecord(record2000);
489
490 mMockTimeInterface.tick();
491
Enrico Granatadbda56f2017-12-18 11:53:22 -0800492 List<IoStatsEntry> aggregateIoStats = mCarStorageMonitoringManager.getAggregateIoStats();
Enrico Granata0f72b742017-11-02 18:26:41 -0700493
494 assertNotNull(aggregateIoStats);
495 assertFalse(aggregateIoStats.isEmpty());
496
497 aggregateIoStats.forEach(serviceIoStat -> {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800498 UidIoRecord mockIoStat = mMockStorageMonitoringInterface.getIoStatsRecord(
Enrico Granata0f72b742017-11-02 18:26:41 -0700499 serviceIoStat.uid);
500
501 assertNotNull(mockIoStat);
502
503 assertTrue(serviceIoStat.representsSameMetrics(mockIoStat));
504 });
505 }
506
Pavel Maltseved2c8642017-12-18 12:56:26 -0800507 @Test
Enrico Granata7e0150d2017-11-06 17:20:17 -0800508 public void testIoStatsDeltas() throws Exception {
509 UidIoRecord oldRecord0 = mMockStorageMonitoringInterface.getIoStatsRecord(0);
510
511 UidIoRecord newRecord0 = new UidIoRecord(0,
512 oldRecord0.foreground_rchar,
513 oldRecord0.foreground_wchar + 100,
514 oldRecord0.foreground_read_bytes,
515 oldRecord0.foreground_write_bytes + 50,
516 oldRecord0.foreground_fsync,
517 oldRecord0.background_rchar,
518 oldRecord0.background_wchar,
519 oldRecord0.background_read_bytes + 100,
520 oldRecord0.background_write_bytes,
521 oldRecord0.background_fsync);
522
523 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord0);
524 mMockTimeInterface.setUptime(500).tick();
525
Enrico Granatadbda56f2017-12-18 11:53:22 -0800526 List<IoStats> deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800527 assertNotNull(deltas);
528 assertEquals(1, deltas.size());
529
Enrico Granatadbda56f2017-12-18 11:53:22 -0800530 IoStats delta0 = deltas.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800531 assertNotNull(delta0);
532 assertEquals(500, delta0.getTimestamp());
533
Enrico Granatadbda56f2017-12-18 11:53:22 -0800534 List<IoStatsEntry> delta0Stats = delta0.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800535 assertNotNull(delta0Stats);
536 assertEquals(1, delta0Stats.size());
537
Enrico Granatadbda56f2017-12-18 11:53:22 -0800538 IoStatsEntry deltaRecord0 = delta0Stats.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800539
540 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
541
542 UidIoRecord newerRecord0 = new UidIoRecord(0,
543 newRecord0.foreground_rchar + 200,
544 newRecord0.foreground_wchar + 10,
545 newRecord0.foreground_read_bytes,
546 newRecord0.foreground_write_bytes,
547 newRecord0.foreground_fsync,
548 newRecord0.background_rchar,
549 newRecord0.background_wchar + 100,
550 newRecord0.background_read_bytes,
551 newRecord0.background_write_bytes + 30,
552 newRecord0.background_fsync + 2);
553
554 mMockStorageMonitoringInterface.addIoStatsRecord(newerRecord0);
555 mMockTimeInterface.setUptime(1000).tick();
556
557 deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
558 assertNotNull(deltas);
559 assertEquals(2, deltas.size());
560
561 delta0 = deltas.get(0);
562 assertNotNull(delta0);
563 assertEquals(500, delta0.getTimestamp());
564
565 delta0Stats = delta0.getStats();
566 assertNotNull(delta0Stats);
567 assertEquals(1, delta0Stats.size());
568
569 deltaRecord0 = delta0Stats.get(0);
570
571 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
572
Enrico Granatadbda56f2017-12-18 11:53:22 -0800573 IoStats delta1 = deltas.get(1);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800574 assertNotNull(delta1);
575 assertEquals(1000, delta1.getTimestamp());
576
Enrico Granatadbda56f2017-12-18 11:53:22 -0800577 List<IoStatsEntry> delta1Stats = delta1.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800578 assertNotNull(delta1Stats);
579 assertEquals(1, delta1Stats.size());
580
581 deltaRecord0 = delta1Stats.get(0);
582
583 assertTrue(deltaRecord0.representsSameMetrics(newerRecord0.delta(newRecord0)));
584 }
585
Pavel Maltseved2c8642017-12-18 12:56:26 -0800586 @Test
Enrico Granata7dce3792017-11-09 14:13:28 -0800587 public void testEventDelivery() throws Exception {
588 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
589
590 UidIoRecord record = new UidIoRecord(0,
591 0,
592 100,
593 0,
594 75,
595 1,
596 0,
597 0,
598 0,
599 0,
600 0);
601
602 Listener listener1 = new Listener("listener1");
603 Listener listener2 = new Listener("listener2");
604
605 mCarStorageMonitoringManager.registerListener(listener1);
606 mCarStorageMonitoringManager.registerListener(listener2);
607
608 mMockStorageMonitoringInterface.addIoStatsRecord(record);
609 mMockTimeInterface.setUptime(500).tick();
610
611 assertTrue(listener1.waitForEvent(eventDeliveryDeadline));
612 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
613
Enrico Granatadbda56f2017-12-18 11:53:22 -0800614 IoStats event1 = listener1.reset();
615 IoStats event2 = listener2.reset();
Enrico Granata7dce3792017-11-09 14:13:28 -0800616
617 assertEquals(event1, event2);
618 event1.getStats().forEach(stats -> assertTrue(stats.representsSameMetrics(record)));
619
620 mCarStorageMonitoringManager.unregisterListener(listener1);
621
622 mMockTimeInterface.setUptime(600).tick();
623 assertFalse(listener1.waitForEvent(eventDeliveryDeadline));
624 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
625 }
626
Pavel Maltseved2c8642017-12-18 12:56:26 -0800627 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800628 public void testIntentOnExcessiveWrite() throws Exception {
629 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
630
631 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
632
633 UidIoRecord record = new UidIoRecord(0,
634 0,
635 5120,
636 0,
637 5000,
638 1,
639 0,
640 7168,
641 0,
642 7000,
643 0);
644
645 mMockStorageMonitoringInterface.addIoStatsRecord(record);
646 mMockTimeInterface.setUptime(500).tick();
647
648 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
649 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
650 assertNotNull(deliveredIntent);
651 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
652 }
653
Pavel Maltseved2c8642017-12-18 12:56:26 -0800654 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800655 public void testIntentOnExcessiveFsync() throws Exception {
656 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
657
658 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
659
660 UidIoRecord record = new UidIoRecord(0,
661 0,
662 0,
663 0,
664 0,
665 2,
666 0,
667 0,
668 0,
669 0,
670 3);
671
672 mMockStorageMonitoringInterface.addIoStatsRecord(record);
673 mMockTimeInterface.setUptime(500).tick();
674
675 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
676 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
677 assertNotNull(deliveredIntent);
678 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
679 }
680
Pavel Maltseved2c8642017-12-18 12:56:26 -0800681 @Test
Enrico Granata88d92c82017-11-30 16:47:15 -0800682 public void testZeroWindowDisablesCollection() throws Exception {
683 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
684
685 UidIoRecord record = new UidIoRecord(0,
686 0,
687 100,
688 0,
689 75,
690 1,
691 0,
692 0,
693 0,
694 0,
695 0);
696
697 Listener listener = new Listener("listener");
698
699 mMockStorageMonitoringInterface.addIoStatsRecord(record);
700 mMockTimeInterface.setUptime(500).tick();
701
702 assertFalse(listener.waitForEvent(eventDeliveryDeadline));
703
704 assertEquals(0, mCarStorageMonitoringManager.getIoStatsDeltas().size());
705 }
706
Enrico Granata1690a622018-01-22 17:34:46 -0800707 @Test
708 public void testComputeShutdownCost() throws Exception {
709 assertEquals(280, mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
710 }
711
712 @Test
713 public void testNegativeShutdownCost() throws Exception {
714 assertEquals(CarStorageMonitoringManager.SHUTDOWN_COST_INFO_MISSING,
715 mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
716 }
717
Pavel Maltseved2c8642017-12-18 12:56:26 -0800718 private String getName() {
719 return mTestName.getMethodName();
720 }
721
Enrico Granatadbda56f2017-12-18 11:53:22 -0800722 static final class Listener implements CarStorageMonitoringManager.IoStatsListener {
Enrico Granata7dce3792017-11-09 14:13:28 -0800723 private final String mName;
724 private final Object mSync = new Object();
725
Enrico Granatadbda56f2017-12-18 11:53:22 -0800726 private IoStats mLastEvent = null;
Enrico Granata7dce3792017-11-09 14:13:28 -0800727
728 Listener(String name) {
729 mName = name;
730 }
731
Enrico Granatadbda56f2017-12-18 11:53:22 -0800732 IoStats reset() {
Enrico Granata7dce3792017-11-09 14:13:28 -0800733 synchronized (mSync) {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800734 IoStats lastEvent = mLastEvent;
Enrico Granata7dce3792017-11-09 14:13:28 -0800735 mLastEvent = null;
736 return lastEvent;
737 }
738 }
739
740 boolean waitForEvent(Duration duration) {
741 long start = SystemClock.elapsedRealtime();
742 long end = start + duration.toMillis();
743 synchronized (mSync) {
744 while (mLastEvent == null && SystemClock.elapsedRealtime() < end) {
745 try {
746 mSync.wait(10L);
747 } catch (InterruptedException e) {
748 // ignore
749 }
750 }
751 }
752
753 return (mLastEvent != null);
754 }
755
756 @Override
Enrico Granatadbda56f2017-12-18 11:53:22 -0800757 public void onSnapshot(IoStats event) {
Enrico Granata7dce3792017-11-09 14:13:28 -0800758 synchronized (mSync) {
759 Log.d(TAG, "listener " + mName + " received event " + event);
760 // We're going to hold a reference to this object
761 mLastEvent = event;
762 mSync.notify();
763 }
764 }
765
766 }
767
Enrico Granatab19bc322017-10-12 12:25:06 -0700768 static final class MockStorageMonitoringInterface implements StorageMonitoringInterface,
769 WearInformationProvider {
770 private WearInformation mWearInformation = null;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800771 private SparseArray<UidIoRecord> mIoStats = new SparseArray<>();
Enrico Granataa97fce22017-10-27 14:57:34 -0700772 private UidIoStatsProvider mIoStatsProvider = () -> mIoStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800773 private LifetimeWriteInfo[] mWriteInfo = new LifetimeWriteInfo[0];
Enrico Granatab19bc322017-10-12 12:25:06 -0700774
775 void setWearInformation(WearInformation wearInformation) {
776 mWearInformation = wearInformation;
777 }
778
Enrico Granata1690a622018-01-22 17:34:46 -0800779 void setWriteInfo(LifetimeWriteInfo[] writeInfo) {
780 mWriteInfo = writeInfo;
781 }
782
Enrico Granata7e0150d2017-11-06 17:20:17 -0800783 void addIoStatsRecord(UidIoRecord record) {
Enrico Granataa97fce22017-10-27 14:57:34 -0700784 mIoStats.append(record.uid, record);
785 }
786
Enrico Granata7e0150d2017-11-06 17:20:17 -0800787 UidIoRecord getIoStatsRecord(int uid) {
Enrico Granata0f72b742017-11-02 18:26:41 -0700788 return mIoStats.get(uid);
789 }
790
Enrico Granataa97fce22017-10-27 14:57:34 -0700791 void deleteIoStatsRecord(int uid) {
792 mIoStats.delete(uid);
793 }
794
Enrico Granatab19bc322017-10-12 12:25:06 -0700795 @Override
796 public WearInformation load() {
797 return mWearInformation;
798 }
799
800 @Override
Enrico Granata1690a622018-01-22 17:34:46 -0800801 public LifetimeWriteInfoProvider getLifetimeWriteInfoProvider() {
802 // cannot make this directly implement because Java does not allow
803 // overloading based on return type and there already is a method named
804 // load() in WearInformationProvider
805 return new LifetimeWriteInfoProvider() {
806 @Override
807 public LifetimeWriteInfo[] load() {
808 return mWriteInfo;
809 }
810 };
811 }
812
813 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700814 public WearInformationProvider[] getFlashWearInformationProviders() {
815 return new WearInformationProvider[] {this};
816 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700817
818 @Override
819 public UidIoStatsProvider getUidIoStatsProvider() {
820 return mIoStatsProvider;
821 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700822 }
823
824 static final class MockTimeInterface implements TimeInterface {
Enrico Granata0f72b742017-11-02 18:26:41 -0700825 private final List<Pair<Runnable, Long>> mActionsList = new ArrayList<>();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800826 private long mUptime = 0;
Enrico Granatab19bc322017-10-12 12:25:06 -0700827
828 @Override
829 public long getUptime(boolean includeDeepSleepTime) {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800830 return mUptime;
Enrico Granatab19bc322017-10-12 12:25:06 -0700831 }
832
833 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700834 public void scheduleAction(Runnable r, long delayMs) {
835 mActionsList.add(Pair.create(r, delayMs));
836 mActionsList.sort(Comparator.comparing(d -> d.second));
837 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700838
839 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700840 public void cancelAllActions() {
841 mActionsList.clear();
842 }
843
844 void tick() {
845 mActionsList.forEach(pair -> pair.first.run());
846 }
Enrico Granata7e0150d2017-11-06 17:20:17 -0800847
848 MockTimeInterface setUptime(long time) {
849 mUptime = time;
850 return this;
851 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700852 }
853
854 static final class MockSystemStateInterface implements SystemStateInterface {
855 private final List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>();
856
857 @Override
858 public void shutdown() {}
859
860 @Override
861 public void enterDeepSleep(int wakeupTimeSec) {}
862
863 @Override
864 public void scheduleActionForBootCompleted(Runnable action, Duration delay) {
865 mActionsList.add(Pair.create(action, delay));
866 mActionsList.sort(Comparator.comparing(d -> d.second));
867 }
868
869 void executeBootCompletedActions() {
870 for (Pair<Runnable, Duration> action : mActionsList) {
871 action.first.run();
872 }
873 }
874 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700875}