blob: a311ca829f514ff6076c6484fd1c5d6e8d2463e7 [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 {
Enrico Granatae7db0002018-02-26 13:52:17 -0800108 put("testAggregateIoStats",
109 new ResourceOverrides() {{
110 override(R.integer.ioStatsNumSamplesToStore, 5);
111 }});
112 put("testIoStatsDeltas",
113 new ResourceOverrides() {{
114 override(R.integer.ioStatsNumSamplesToStore, 5);
115 }});
116 put("testEventDelivery",
117 new ResourceOverrides() {{
118 override(R.integer.ioStatsNumSamplesToStore, 5);
119 }});
Enrico Granata43024de2017-11-16 17:09:37 -0800120 put("testIntentOnExcessiveWrite",
121 new ResourceOverrides() {{
Enrico Granatae7db0002018-02-26 13:52:17 -0800122 override(R.integer.ioStatsNumSamplesToStore, 5);
Enrico Granata43024de2017-11-16 17:09:37 -0800123 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
124 override(R.integer.acceptableWrittenKBytesPerSample, 10);
125 override(R.integer.acceptableFsyncCallsPerSample, 1000);
126 override(R.string.intentReceiverForUnacceptableIoMetrics,
Pavel Maltseved2c8642017-12-18 12:56:26 -0800127 getFlattenComponent(
128 CarStorageMonitoringBroadcastReceiver.class));
Enrico Granata43024de2017-11-16 17:09:37 -0800129 }});
130
131 put("testIntentOnExcessiveFsync",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800132 new ResourceOverrides() {{
Enrico Granatae7db0002018-02-26 13:52:17 -0800133 override(R.integer.ioStatsNumSamplesToStore, 5);
Pavel Maltseved2c8642017-12-18 12:56:26 -0800134 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
135 override(R.integer.acceptableWrittenKBytesPerSample, 1000);
136 override(R.integer.acceptableFsyncCallsPerSample, 2);
137 override(R.string.intentReceiverForUnacceptableIoMetrics,
138 getFlattenComponent(
139 CarStorageMonitoringBroadcastReceiver.class));
140 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800141
142 put("testZeroWindowDisablesCollection",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800143 new ResourceOverrides() {{
144 override(R.integer.ioStatsNumSamplesToStore, 0);
145 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800146
Enrico Granata43024de2017-11-16 17:09:37 -0800147 }
148 };
149
Enrico Granataa97fce22017-10-27 14:57:34 -0700150 private static final class TestData {
151 static final TestData DEFAULT = new TestData(0, DEFAULT_WEAR_INFORMATION, null, null);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700152
153 final long uptime;
154 @NonNull
155 final WearInformation wearInformation;
156 @Nullable
157 final WearHistory wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700158 @NonNull
Enrico Granata7e0150d2017-11-06 17:20:17 -0800159 final UidIoRecord[] ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800160 @NonNull
161 final LifetimeWriteInfo[] previousLifetimeWriteInfo;
162 @NonNull
163 final LifetimeWriteInfo[] currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700164
Enrico Granata43024de2017-11-16 17:09:37 -0800165
Enrico Granataa97fce22017-10-27 14:57:34 -0700166 TestData(long uptime,
Enrico Granata1690a622018-01-22 17:34:46 -0800167 @Nullable WearInformation wearInformation,
168 @Nullable WearHistory wearHistory,
169 @Nullable UidIoRecord[] ioStats) {
170 this(uptime, wearInformation, wearHistory, ioStats, null, null);
171 }
172
173 TestData(long uptime,
Enrico Granataa97fce22017-10-27 14:57:34 -0700174 @Nullable WearInformation wearInformation,
175 @Nullable WearHistory wearHistory,
Enrico Granata1690a622018-01-22 17:34:46 -0800176 @Nullable UidIoRecord[] ioStats,
177 @Nullable LifetimeWriteInfo[] previousLifetimeWriteInfo,
178 @Nullable LifetimeWriteInfo[] currentLifetimeWriteInfo) {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700179 if (wearInformation == null) wearInformation = DEFAULT_WEAR_INFORMATION;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800180 if (ioStats == null) ioStats = new UidIoRecord[0];
Enrico Granata1690a622018-01-22 17:34:46 -0800181 if (previousLifetimeWriteInfo == null) {
182 previousLifetimeWriteInfo = new LifetimeWriteInfo[0];
183 }
184 if (currentLifetimeWriteInfo == null) {
185 currentLifetimeWriteInfo = new LifetimeWriteInfo[0];
186 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700187 this.uptime = uptime;
188 this.wearInformation = wearInformation;
189 this.wearHistory = wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700190 this.ioStats = ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800191 this.previousLifetimeWriteInfo = previousLifetimeWriteInfo;
192 this.currentLifetimeWriteInfo = currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700193 }
194 }
195
Enrico Granataa97fce22017-10-27 14:57:34 -0700196 private static final Map<String, TestData> PER_TEST_DATA =
Enrico Granata7e0150d2017-11-06 17:20:17 -0800197 new HashMap<String, TestData>() {
198 {
199 put("testReadWearHistory",
200 new TestData(6500, DEFAULT_WEAR_INFORMATION,
201 WearHistory.fromRecords(
202 WearEstimateRecord.Builder.newBuilder()
203 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
204 .toWearEstimate(new WearEstimate(10, 0))
205 .atUptime(1000)
206 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
207 WearEstimateRecord.Builder.newBuilder()
208 .fromWearEstimate(new WearEstimate(10, 0))
209 .toWearEstimate(new WearEstimate(20, 0))
210 .atUptime(4000)
211 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
212 WearEstimateRecord.Builder.newBuilder()
213 .fromWearEstimate(new WearEstimate(20, 0))
214 .toWearEstimate(new WearEstimate(30, 0))
215 .atUptime(6500)
216 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700217
Enrico Granata7e0150d2017-11-06 17:20:17 -0800218 put("testNotAcceptableWearEvent",
219 new TestData(2520006499L,
220 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
221 WearHistory.fromRecords(
222 WearEstimateRecord.Builder.newBuilder()
223 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
224 .toWearEstimate(new WearEstimate(10, 0))
225 .atUptime(1000)
226 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
227 WearEstimateRecord.Builder.newBuilder()
228 .fromWearEstimate(new WearEstimate(10, 0))
229 .toWearEstimate(new WearEstimate(20, 0))
230 .atUptime(4000)
231 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
232 WearEstimateRecord.Builder.newBuilder()
233 .fromWearEstimate(new WearEstimate(20, 0))
234 .toWearEstimate(new WearEstimate(30, 0))
235 .atUptime(6500)
236 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700237
Enrico Granata7e0150d2017-11-06 17:20:17 -0800238 put("testAcceptableWearEvent",
239 new TestData(2520006501L,
240 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
241 WearHistory.fromRecords(
242 WearEstimateRecord.Builder.newBuilder()
243 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
244 .toWearEstimate(new WearEstimate(10, 0))
245 .atUptime(1000)
246 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
247 WearEstimateRecord.Builder.newBuilder()
248 .fromWearEstimate(new WearEstimate(10, 0))
249 .toWearEstimate(new WearEstimate(20, 0))
250 .atUptime(4000)
251 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
252 WearEstimateRecord.Builder.newBuilder()
253 .fromWearEstimate(new WearEstimate(20, 0))
254 .toWearEstimate(new WearEstimate(30, 0))
255 .atUptime(6500)
256 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granataa97fce22017-10-27 14:57:34 -0700257
Enrico Granata7e0150d2017-11-06 17:20:17 -0800258 put("testBootIoStats",
259 new TestData(1000L,
260 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
261 null,
262 new UidIoRecord[]{
263 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
264 0, 0, 0, 0, 0),
265 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
266 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700267
Enrico Granata7e0150d2017-11-06 17:20:17 -0800268 put("testAggregateIoStats",
269 new TestData(1000L,
270 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
271 null,
272 new UidIoRecord[]{
273 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
274 0, 0, 0, 0, 0),
275 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
276 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700277
Enrico Granata7e0150d2017-11-06 17:20:17 -0800278 put("testIoStatsDeltas",
279 new TestData(1000L,
280 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
281 null,
282 new UidIoRecord[]{
283 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
284 0, 0, 0, 0, 0)}));
Enrico Granata1690a622018-01-22 17:34:46 -0800285
286 put("testComputeShutdownCost",
287 new TestData(1000L,
288 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
289 null,
290 null,
291 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
292 new LifetimeWriteInfo("p2", "ext4", 100),
293 new LifetimeWriteInfo("p3", "f2fs", 100)},
294 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
295 new LifetimeWriteInfo("p2", "ext4", 300),
296 new LifetimeWriteInfo("p3", "f2fs", 100)}));
297
298 put("testNegativeShutdownCost",
299 new TestData(1000L,
300 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
301 null,
302 null,
303 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
304 new LifetimeWriteInfo("p2", "ext4", 100),
305 new LifetimeWriteInfo("p3", "f2fs", 200)},
306 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
307 new LifetimeWriteInfo("p2", "ext4", 300),
308 new LifetimeWriteInfo("p3", "f2fs", 100)}));
Enrico Granata7e0150d2017-11-06 17:20:17 -0800309 }};
Enrico Granata1172f882017-09-21 14:51:30 -0700310
Enrico Granatab19bc322017-10-12 12:25:06 -0700311 private final MockSystemStateInterface mMockSystemStateInterface =
312 new MockSystemStateInterface();
313 private final MockStorageMonitoringInterface mMockStorageMonitoringInterface =
314 new MockStorageMonitoringInterface();
Enrico Granata0f72b742017-11-02 18:26:41 -0700315 private final MockTimeInterface mMockTimeInterface =
316 new MockTimeInterface();
Enrico Granatab19bc322017-10-12 12:25:06 -0700317
Enrico Granata517a1e02017-09-20 16:15:50 -0700318 private CarStorageMonitoringManager mCarStorageMonitoringManager;
319
320 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700321 protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() {
322 SystemInterface.Builder builder = super.getSystemInterfaceBuilder();
323 return builder.withSystemStateInterface(mMockSystemStateInterface)
324 .withStorageMonitoringInterface(mMockStorageMonitoringInterface)
Enrico Granata0f72b742017-11-02 18:26:41 -0700325 .withTimeInterface(mMockTimeInterface);
Enrico Granatab19bc322017-10-12 12:25:06 -0700326 }
327
328 @Override
Enrico Granata517a1e02017-09-20 16:15:50 -0700329 protected synchronized void configureFakeSystemInterface() {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700330 try {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800331 final TestData wearData = PER_TEST_DATA.getOrDefault(getName(), TestData.DEFAULT);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700332 final WearHistory wearHistory = wearData.wearHistory;
333
Enrico Granatab19bc322017-10-12 12:25:06 -0700334 mMockStorageMonitoringInterface.setWearInformation(wearData.wearInformation);
Enrico Granata1690a622018-01-22 17:34:46 -0800335 mMockStorageMonitoringInterface.setWriteInfo(wearData.currentLifetimeWriteInfo);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700336
337 if (wearHistory != null) {
338 File wearHistoryFile = new File(getFakeSystemInterface().getFilesDir(),
339 CarStorageMonitoringService.WEAR_INFO_FILENAME);
340 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(wearHistoryFile))) {
341 wearHistory.writeToJson(jsonWriter);
342 }
343 }
344
345 if (wearData.uptime > 0) {
346 File uptimeFile = new File(getFakeSystemInterface().getFilesDir(),
Enrico Granatab19bc322017-10-12 12:25:06 -0700347 CarStorageMonitoringService.UPTIME_TRACKER_FILENAME);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700348 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(uptimeFile))) {
349 jsonWriter.beginObject();
350 jsonWriter.name("uptime").value(wearData.uptime);
351 jsonWriter.endObject();
352 }
353 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700354
Enrico Granata1690a622018-01-22 17:34:46 -0800355 if (wearData.previousLifetimeWriteInfo.length > 0) {
356 File previousLifetimeFile = new File(getFakeSystemInterface().getFilesDir(),
357 CarStorageMonitoringService.LIFETIME_WRITES_FILENAME);
358 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(previousLifetimeFile))) {
359 jsonWriter.beginObject();
360 jsonWriter.name("lifetimeWriteInfo").beginArray();
361 for (LifetimeWriteInfo writeInfo : wearData.previousLifetimeWriteInfo) {
362 writeInfo.writeToJson(jsonWriter);
363 }
364 jsonWriter.endArray().endObject();
365 }
366 }
367
Enrico Granataa97fce22017-10-27 14:57:34 -0700368 Arrays.stream(wearData.ioStats).forEach(
369 mMockStorageMonitoringInterface::addIoStatsRecord);
370
Enrico Granata286cd8e2017-09-25 14:46:49 -0700371 } catch (IOException e) {
372 Log.e(TAG, "failed to configure fake system interface", e);
373 fail("failed to configure fake system interface instance");
374 }
Enrico Granata43024de2017-11-16 17:09:37 -0800375 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700376
Enrico Granata43024de2017-11-16 17:09:37 -0800377 @Override
378 protected synchronized void configureResourceOverrides(MockResources resources) {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800379 final ResourceOverrides overrides = PER_TEST_RESOURCES.getOrDefault(getName(), null);
Enrico Granata43024de2017-11-16 17:09:37 -0800380 if (overrides != null) {
381 overrides.overrideResources(resources);
382 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700383 }
384
385 @Override
Pavel Maltseved2c8642017-12-18 12:56:26 -0800386 public void setUp() throws Exception {
Enrico Granata517a1e02017-09-20 16:15:50 -0700387 super.setUp();
Enrico Granatab19bc322017-10-12 12:25:06 -0700388 mMockSystemStateInterface.executeBootCompletedActions();
Enrico Granatacf53fd72017-09-28 10:45:44 -0700389
Enrico Granata517a1e02017-09-20 16:15:50 -0700390 mCarStorageMonitoringManager =
391 (CarStorageMonitoringManager) getCar().getCarManager(Car.STORAGE_MONITORING_SERVICE);
392 }
393
Pavel Maltseved2c8642017-12-18 12:56:26 -0800394 @Test
Enrico Granata517a1e02017-09-20 16:15:50 -0700395 public void testReadPreEolInformation() throws Exception {
Enrico Granata1172f882017-09-21 14:51:30 -0700396 assertEquals(DEFAULT_WEAR_INFORMATION.preEolInfo,
Enrico Granata517a1e02017-09-20 16:15:50 -0700397 mCarStorageMonitoringManager.getPreEolIndicatorStatus());
398 }
Enrico Granata1172f882017-09-21 14:51:30 -0700399
Pavel Maltseved2c8642017-12-18 12:56:26 -0800400 @Test
Enrico Granata1172f882017-09-21 14:51:30 -0700401 public void testReadWearEstimate() throws Exception {
402 final WearEstimate wearEstimate = mCarStorageMonitoringManager.getWearEstimate();
403
404 assertNotNull(wearEstimate);
405 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateA, wearEstimate.typeA);
406 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateB, wearEstimate.typeB);
407 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700408
Pavel Maltseved2c8642017-12-18 12:56:26 -0800409 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700410 public void testReadWearHistory() throws Exception {
411 final List<WearEstimateChange> wearEstimateChanges =
412 mCarStorageMonitoringManager.getWearEstimateHistory();
413
414 assertNotNull(wearEstimateChanges);
415 assertFalse(wearEstimateChanges.isEmpty());
416
Enrico Granataa97fce22017-10-27 14:57:34 -0700417 final WearHistory expectedWearHistory = PER_TEST_DATA.get(getName()).wearHistory;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700418
419 assertEquals(expectedWearHistory.size(), wearEstimateChanges.size());
420 for (int i = 0; i < wearEstimateChanges.size(); ++i) {
421 final WearEstimateRecord expected = expectedWearHistory.get(i);
422 final WearEstimateChange actual = wearEstimateChanges.get(i);
423
424 assertTrue(expected.isSameAs(actual));
425 }
426 }
427
428 private void checkLastWearEvent(boolean isAcceptable) throws Exception {
429 final List<WearEstimateChange> wearEstimateChanges =
430 mCarStorageMonitoringManager.getWearEstimateHistory();
431
432 assertNotNull(wearEstimateChanges);
433 assertFalse(wearEstimateChanges.isEmpty());
434
Enrico Granataa97fce22017-10-27 14:57:34 -0700435 final TestData wearData = PER_TEST_DATA.get(getName());
Enrico Granata286cd8e2017-09-25 14:46:49 -0700436
437 final WearInformation expectedCurrentWear = wearData.wearInformation;
438 final WearEstimate expectedPreviousWear = wearData.wearHistory.getLast().getNewWearEstimate();
439
440 final WearEstimateChange actualCurrentWear =
441 wearEstimateChanges.get(wearEstimateChanges.size() - 1);
442
443 assertEquals(isAcceptable, actualCurrentWear.isAcceptableDegradation);
444 assertEquals(expectedCurrentWear.toWearEstimate(), actualCurrentWear.newEstimate);
445 assertEquals(expectedPreviousWear, actualCurrentWear.oldEstimate);
446 }
447
Pavel Maltseved2c8642017-12-18 12:56:26 -0800448 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700449 public void testNotAcceptableWearEvent() throws Exception {
450 checkLastWearEvent(false);
451 }
452
Pavel Maltseved2c8642017-12-18 12:56:26 -0800453 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700454 public void testAcceptableWearEvent() throws Exception {
455 checkLastWearEvent(true);
456 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700457
Pavel Maltseved2c8642017-12-18 12:56:26 -0800458 @Test
Enrico Granataa97fce22017-10-27 14:57:34 -0700459 public void testBootIoStats() throws Exception {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800460 final List<IoStatsEntry> bootIoStats =
Enrico Granataa97fce22017-10-27 14:57:34 -0700461 mCarStorageMonitoringManager.getBootIoStats();
462
463 assertNotNull(bootIoStats);
464 assertFalse(bootIoStats.isEmpty());
465
Enrico Granata7e0150d2017-11-06 17:20:17 -0800466 final UidIoRecord[] bootIoRecords = PER_TEST_DATA.get(getName()).ioStats;
Enrico Granataa97fce22017-10-27 14:57:34 -0700467
468 bootIoStats.forEach(uidIoStats -> assertTrue(Arrays.stream(bootIoRecords).anyMatch(
469 ioRecord -> uidIoStats.representsSameMetrics(ioRecord))));
470 }
471
Pavel Maltseved2c8642017-12-18 12:56:26 -0800472 @Test
Enrico Granata0f72b742017-11-02 18:26:41 -0700473 public void testAggregateIoStats() throws Exception {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800474 UidIoRecord oldRecord1000 = mMockStorageMonitoringInterface.getIoStatsRecord(1000);
Enrico Granata0f72b742017-11-02 18:26:41 -0700475
Enrico Granata7e0150d2017-11-06 17:20:17 -0800476 UidIoRecord newRecord1000 = new UidIoRecord(1000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700477 oldRecord1000.foreground_rchar,
478 oldRecord1000.foreground_wchar + 50,
479 oldRecord1000.foreground_read_bytes,
480 oldRecord1000.foreground_write_bytes + 100,
481 oldRecord1000.foreground_fsync + 1,
482 oldRecord1000.background_rchar,
483 oldRecord1000.background_wchar,
484 oldRecord1000.background_read_bytes,
485 oldRecord1000.background_write_bytes,
486 oldRecord1000.background_fsync);
487
488 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord1000);
489
Enrico Granata7e0150d2017-11-06 17:20:17 -0800490 UidIoRecord record2000 = new UidIoRecord(2000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700491 1024,
492 2048,
493 0,
494 1024,
495 1,
496 0,
497 0,
498 0,
499 0,
500 0);
501
502 mMockStorageMonitoringInterface.addIoStatsRecord(record2000);
503
504 mMockTimeInterface.tick();
505
Enrico Granatadbda56f2017-12-18 11:53:22 -0800506 List<IoStatsEntry> aggregateIoStats = mCarStorageMonitoringManager.getAggregateIoStats();
Enrico Granata0f72b742017-11-02 18:26:41 -0700507
508 assertNotNull(aggregateIoStats);
509 assertFalse(aggregateIoStats.isEmpty());
510
511 aggregateIoStats.forEach(serviceIoStat -> {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800512 UidIoRecord mockIoStat = mMockStorageMonitoringInterface.getIoStatsRecord(
Enrico Granata0f72b742017-11-02 18:26:41 -0700513 serviceIoStat.uid);
514
515 assertNotNull(mockIoStat);
516
517 assertTrue(serviceIoStat.representsSameMetrics(mockIoStat));
518 });
519 }
520
Pavel Maltseved2c8642017-12-18 12:56:26 -0800521 @Test
Enrico Granata7e0150d2017-11-06 17:20:17 -0800522 public void testIoStatsDeltas() throws Exception {
523 UidIoRecord oldRecord0 = mMockStorageMonitoringInterface.getIoStatsRecord(0);
524
525 UidIoRecord newRecord0 = new UidIoRecord(0,
526 oldRecord0.foreground_rchar,
527 oldRecord0.foreground_wchar + 100,
528 oldRecord0.foreground_read_bytes,
529 oldRecord0.foreground_write_bytes + 50,
530 oldRecord0.foreground_fsync,
531 oldRecord0.background_rchar,
532 oldRecord0.background_wchar,
533 oldRecord0.background_read_bytes + 100,
534 oldRecord0.background_write_bytes,
535 oldRecord0.background_fsync);
536
537 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord0);
538 mMockTimeInterface.setUptime(500).tick();
539
Enrico Granatadbda56f2017-12-18 11:53:22 -0800540 List<IoStats> deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800541 assertNotNull(deltas);
542 assertEquals(1, deltas.size());
543
Enrico Granatadbda56f2017-12-18 11:53:22 -0800544 IoStats delta0 = deltas.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800545 assertNotNull(delta0);
546 assertEquals(500, delta0.getTimestamp());
547
Enrico Granatadbda56f2017-12-18 11:53:22 -0800548 List<IoStatsEntry> delta0Stats = delta0.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800549 assertNotNull(delta0Stats);
550 assertEquals(1, delta0Stats.size());
551
Enrico Granatadbda56f2017-12-18 11:53:22 -0800552 IoStatsEntry deltaRecord0 = delta0Stats.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800553
554 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
555
556 UidIoRecord newerRecord0 = new UidIoRecord(0,
557 newRecord0.foreground_rchar + 200,
558 newRecord0.foreground_wchar + 10,
559 newRecord0.foreground_read_bytes,
560 newRecord0.foreground_write_bytes,
561 newRecord0.foreground_fsync,
562 newRecord0.background_rchar,
563 newRecord0.background_wchar + 100,
564 newRecord0.background_read_bytes,
565 newRecord0.background_write_bytes + 30,
566 newRecord0.background_fsync + 2);
567
568 mMockStorageMonitoringInterface.addIoStatsRecord(newerRecord0);
569 mMockTimeInterface.setUptime(1000).tick();
570
571 deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
572 assertNotNull(deltas);
573 assertEquals(2, deltas.size());
574
575 delta0 = deltas.get(0);
576 assertNotNull(delta0);
577 assertEquals(500, delta0.getTimestamp());
578
579 delta0Stats = delta0.getStats();
580 assertNotNull(delta0Stats);
581 assertEquals(1, delta0Stats.size());
582
583 deltaRecord0 = delta0Stats.get(0);
584
585 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
586
Enrico Granatadbda56f2017-12-18 11:53:22 -0800587 IoStats delta1 = deltas.get(1);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800588 assertNotNull(delta1);
589 assertEquals(1000, delta1.getTimestamp());
590
Enrico Granatadbda56f2017-12-18 11:53:22 -0800591 List<IoStatsEntry> delta1Stats = delta1.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800592 assertNotNull(delta1Stats);
593 assertEquals(1, delta1Stats.size());
594
595 deltaRecord0 = delta1Stats.get(0);
596
597 assertTrue(deltaRecord0.representsSameMetrics(newerRecord0.delta(newRecord0)));
598 }
599
Pavel Maltseved2c8642017-12-18 12:56:26 -0800600 @Test
Enrico Granata7dce3792017-11-09 14:13:28 -0800601 public void testEventDelivery() throws Exception {
602 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
603
604 UidIoRecord record = new UidIoRecord(0,
605 0,
606 100,
607 0,
608 75,
609 1,
610 0,
611 0,
612 0,
613 0,
614 0);
615
616 Listener listener1 = new Listener("listener1");
617 Listener listener2 = new Listener("listener2");
618
619 mCarStorageMonitoringManager.registerListener(listener1);
620 mCarStorageMonitoringManager.registerListener(listener2);
621
622 mMockStorageMonitoringInterface.addIoStatsRecord(record);
623 mMockTimeInterface.setUptime(500).tick();
624
625 assertTrue(listener1.waitForEvent(eventDeliveryDeadline));
626 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
627
Enrico Granatadbda56f2017-12-18 11:53:22 -0800628 IoStats event1 = listener1.reset();
629 IoStats event2 = listener2.reset();
Enrico Granata7dce3792017-11-09 14:13:28 -0800630
631 assertEquals(event1, event2);
632 event1.getStats().forEach(stats -> assertTrue(stats.representsSameMetrics(record)));
633
634 mCarStorageMonitoringManager.unregisterListener(listener1);
635
636 mMockTimeInterface.setUptime(600).tick();
637 assertFalse(listener1.waitForEvent(eventDeliveryDeadline));
638 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
639 }
640
Pavel Maltseved2c8642017-12-18 12:56:26 -0800641 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800642 public void testIntentOnExcessiveWrite() throws Exception {
643 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
644
645 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
646
647 UidIoRecord record = new UidIoRecord(0,
648 0,
649 5120,
650 0,
651 5000,
652 1,
653 0,
654 7168,
655 0,
656 7000,
657 0);
658
659 mMockStorageMonitoringInterface.addIoStatsRecord(record);
660 mMockTimeInterface.setUptime(500).tick();
661
662 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
663 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
664 assertNotNull(deliveredIntent);
665 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
666 }
667
Pavel Maltseved2c8642017-12-18 12:56:26 -0800668 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800669 public void testIntentOnExcessiveFsync() throws Exception {
670 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
671
672 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
673
674 UidIoRecord record = new UidIoRecord(0,
675 0,
676 0,
677 0,
678 0,
679 2,
680 0,
681 0,
682 0,
683 0,
684 3);
685
686 mMockStorageMonitoringInterface.addIoStatsRecord(record);
687 mMockTimeInterface.setUptime(500).tick();
688
689 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
690 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
691 assertNotNull(deliveredIntent);
692 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
693 }
694
Pavel Maltseved2c8642017-12-18 12:56:26 -0800695 @Test
Enrico Granata88d92c82017-11-30 16:47:15 -0800696 public void testZeroWindowDisablesCollection() throws Exception {
697 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
698
699 UidIoRecord record = new UidIoRecord(0,
700 0,
701 100,
702 0,
703 75,
704 1,
705 0,
706 0,
707 0,
708 0,
709 0);
710
711 Listener listener = new Listener("listener");
712
713 mMockStorageMonitoringInterface.addIoStatsRecord(record);
714 mMockTimeInterface.setUptime(500).tick();
715
716 assertFalse(listener.waitForEvent(eventDeliveryDeadline));
717
718 assertEquals(0, mCarStorageMonitoringManager.getIoStatsDeltas().size());
719 }
720
Enrico Granata1690a622018-01-22 17:34:46 -0800721 @Test
722 public void testComputeShutdownCost() throws Exception {
723 assertEquals(280, mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
724 }
725
726 @Test
727 public void testNegativeShutdownCost() throws Exception {
728 assertEquals(CarStorageMonitoringManager.SHUTDOWN_COST_INFO_MISSING,
729 mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
730 }
731
Pavel Maltseved2c8642017-12-18 12:56:26 -0800732 private String getName() {
733 return mTestName.getMethodName();
734 }
735
Enrico Granatadbda56f2017-12-18 11:53:22 -0800736 static final class Listener implements CarStorageMonitoringManager.IoStatsListener {
Enrico Granata7dce3792017-11-09 14:13:28 -0800737 private final String mName;
738 private final Object mSync = new Object();
739
Enrico Granatadbda56f2017-12-18 11:53:22 -0800740 private IoStats mLastEvent = null;
Enrico Granata7dce3792017-11-09 14:13:28 -0800741
742 Listener(String name) {
743 mName = name;
744 }
745
Enrico Granatadbda56f2017-12-18 11:53:22 -0800746 IoStats reset() {
Enrico Granata7dce3792017-11-09 14:13:28 -0800747 synchronized (mSync) {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800748 IoStats lastEvent = mLastEvent;
Enrico Granata7dce3792017-11-09 14:13:28 -0800749 mLastEvent = null;
750 return lastEvent;
751 }
752 }
753
754 boolean waitForEvent(Duration duration) {
755 long start = SystemClock.elapsedRealtime();
756 long end = start + duration.toMillis();
757 synchronized (mSync) {
758 while (mLastEvent == null && SystemClock.elapsedRealtime() < end) {
759 try {
760 mSync.wait(10L);
761 } catch (InterruptedException e) {
762 // ignore
763 }
764 }
765 }
766
767 return (mLastEvent != null);
768 }
769
770 @Override
Enrico Granatadbda56f2017-12-18 11:53:22 -0800771 public void onSnapshot(IoStats event) {
Enrico Granata7dce3792017-11-09 14:13:28 -0800772 synchronized (mSync) {
773 Log.d(TAG, "listener " + mName + " received event " + event);
774 // We're going to hold a reference to this object
775 mLastEvent = event;
776 mSync.notify();
777 }
778 }
779
780 }
781
Enrico Granatab19bc322017-10-12 12:25:06 -0700782 static final class MockStorageMonitoringInterface implements StorageMonitoringInterface,
783 WearInformationProvider {
784 private WearInformation mWearInformation = null;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800785 private SparseArray<UidIoRecord> mIoStats = new SparseArray<>();
Enrico Granataa97fce22017-10-27 14:57:34 -0700786 private UidIoStatsProvider mIoStatsProvider = () -> mIoStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800787 private LifetimeWriteInfo[] mWriteInfo = new LifetimeWriteInfo[0];
Enrico Granatab19bc322017-10-12 12:25:06 -0700788
789 void setWearInformation(WearInformation wearInformation) {
790 mWearInformation = wearInformation;
791 }
792
Enrico Granata1690a622018-01-22 17:34:46 -0800793 void setWriteInfo(LifetimeWriteInfo[] writeInfo) {
794 mWriteInfo = writeInfo;
795 }
796
Enrico Granata7e0150d2017-11-06 17:20:17 -0800797 void addIoStatsRecord(UidIoRecord record) {
Enrico Granataa97fce22017-10-27 14:57:34 -0700798 mIoStats.append(record.uid, record);
799 }
800
Enrico Granata7e0150d2017-11-06 17:20:17 -0800801 UidIoRecord getIoStatsRecord(int uid) {
Enrico Granata0f72b742017-11-02 18:26:41 -0700802 return mIoStats.get(uid);
803 }
804
Enrico Granataa97fce22017-10-27 14:57:34 -0700805 void deleteIoStatsRecord(int uid) {
806 mIoStats.delete(uid);
807 }
808
Enrico Granatab19bc322017-10-12 12:25:06 -0700809 @Override
810 public WearInformation load() {
811 return mWearInformation;
812 }
813
814 @Override
Enrico Granata1690a622018-01-22 17:34:46 -0800815 public LifetimeWriteInfoProvider getLifetimeWriteInfoProvider() {
816 // cannot make this directly implement because Java does not allow
817 // overloading based on return type and there already is a method named
818 // load() in WearInformationProvider
819 return new LifetimeWriteInfoProvider() {
820 @Override
821 public LifetimeWriteInfo[] load() {
822 return mWriteInfo;
823 }
824 };
825 }
826
827 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700828 public WearInformationProvider[] getFlashWearInformationProviders() {
829 return new WearInformationProvider[] {this};
830 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700831
832 @Override
833 public UidIoStatsProvider getUidIoStatsProvider() {
834 return mIoStatsProvider;
835 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700836 }
837
838 static final class MockTimeInterface implements TimeInterface {
Enrico Granata0f72b742017-11-02 18:26:41 -0700839 private final List<Pair<Runnable, Long>> mActionsList = new ArrayList<>();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800840 private long mUptime = 0;
Enrico Granatab19bc322017-10-12 12:25:06 -0700841
842 @Override
843 public long getUptime(boolean includeDeepSleepTime) {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800844 return mUptime;
Enrico Granatab19bc322017-10-12 12:25:06 -0700845 }
846
847 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700848 public void scheduleAction(Runnable r, long delayMs) {
849 mActionsList.add(Pair.create(r, delayMs));
850 mActionsList.sort(Comparator.comparing(d -> d.second));
851 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700852
853 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700854 public void cancelAllActions() {
855 mActionsList.clear();
856 }
857
858 void tick() {
859 mActionsList.forEach(pair -> pair.first.run());
860 }
Enrico Granata7e0150d2017-11-06 17:20:17 -0800861
862 MockTimeInterface setUptime(long time) {
863 mUptime = time;
864 return this;
865 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700866 }
867
868 static final class MockSystemStateInterface implements SystemStateInterface {
869 private final List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>();
870
871 @Override
872 public void shutdown() {}
873
874 @Override
Steve Paik0f9fc002018-02-09 17:42:00 -0800875 public boolean enterDeepSleep(int wakeupTimeSec) {
876 return true;
877 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700878
879 @Override
880 public void scheduleActionForBootCompleted(Runnable action, Duration delay) {
881 mActionsList.add(Pair.create(action, delay));
882 mActionsList.sort(Comparator.comparing(d -> d.second));
883 }
884
885 void executeBootCompletedActions() {
886 for (Pair<Runnable, Duration> action : mActionsList) {
887 action.first.run();
888 }
889 }
890 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700891}