blob: f034ccb24c3e2421156ba9a9df951a66b41a9c7f [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.IoStats;
Steve Paik07db5ed2018-09-24 16:48:52 -070031import android.car.storagemonitoring.IoStatsEntry;
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 Granata57738692018-02-23 15:35:07 -080037import android.content.pm.PackageManager.NameNotFoundException;
38import android.content.pm.ResolveInfo;
Enrico Granata7dce3792017-11-09 14:13:28 -080039import android.os.SystemClock;
Pavel Maltseved2c8642017-12-18 12:56:26 -080040import android.support.test.filters.MediumTest;
41import android.support.test.runner.AndroidJUnit4;
Enrico Granata286cd8e2017-09-25 14:46:49 -070042import android.util.JsonWriter;
43import android.util.Log;
Enrico Granatab19bc322017-10-12 12:25:06 -070044import android.util.Pair;
Enrico Granataa97fce22017-10-27 14:57:34 -070045import android.util.SparseArray;
Pavel Maltseved2c8642017-12-18 12:56:26 -080046
Enrico Granata1690a622018-01-22 17:34:46 -080047import com.android.car.storagemonitoring.LifetimeWriteInfoProvider;
Enrico Granataa97fce22017-10-27 14:57:34 -070048import com.android.car.storagemonitoring.UidIoStatsProvider;
Enrico Granata286cd8e2017-09-25 14:46:49 -070049import com.android.car.storagemonitoring.WearEstimateRecord;
50import com.android.car.storagemonitoring.WearHistory;
Enrico Granata517a1e02017-09-20 16:15:50 -070051import com.android.car.storagemonitoring.WearInformation;
Enrico Granatab19bc322017-10-12 12:25:06 -070052import com.android.car.storagemonitoring.WearInformationProvider;
53import com.android.car.systeminterface.StorageMonitoringInterface;
54import com.android.car.systeminterface.SystemInterface;
55import com.android.car.systeminterface.SystemStateInterface;
56import com.android.car.systeminterface.TimeInterface;
Pavel Maltseved2c8642017-12-18 12:56:26 -080057
58import org.junit.Rule;
59import org.junit.Test;
60import org.junit.rules.TestName;
61import org.junit.runner.RunWith;
62
Enrico Granata286cd8e2017-09-25 14:46:49 -070063import java.io.File;
64import java.io.FileWriter;
65import java.io.IOException;
Enrico Granatab19bc322017-10-12 12:25:06 -070066import java.time.Duration;
Enrico Granata286cd8e2017-09-25 14:46:49 -070067import java.time.Instant;
Enrico Granatab19bc322017-10-12 12:25:06 -070068import java.util.ArrayList;
Enrico Granataa97fce22017-10-27 14:57:34 -070069import java.util.Arrays;
Enrico Granatab19bc322017-10-12 12:25:06 -070070import java.util.Comparator;
Enrico Granata286cd8e2017-09-25 14:46:49 -070071import java.util.HashMap;
72import java.util.List;
73import java.util.Map;
Steve Paik07db5ed2018-09-24 16:48:52 -070074import java.util.Objects;
Enrico Granata517a1e02017-09-20 16:15:50 -070075
76/** Test the public entry points for the CarStorageMonitoringManager */
Pavel Maltseved2c8642017-12-18 12:56:26 -080077@RunWith(AndroidJUnit4.class)
Enrico Granata517a1e02017-09-20 16:15:50 -070078@MediumTest
79public class CarStorageMonitoringTest extends MockedCarTestBase {
80 private static final String TAG = CarStorageMonitoringTest.class.getSimpleName();
81
Pavel Maltseved2c8642017-12-18 12:56:26 -080082 @Rule public TestName mTestName = new TestName();
83
Enrico Granata1172f882017-09-21 14:51:30 -070084 private static final WearInformation DEFAULT_WEAR_INFORMATION =
Enrico Granata286cd8e2017-09-25 14:46:49 -070085 new WearInformation(30, 0, WearInformation.PRE_EOL_INFO_NORMAL);
86
Enrico Granata57738692018-02-23 15:35:07 -080087 final class TestContext extends MockContext {
88 TestContext(MockContext context) {
89 super(context.getBaseContext());
90 }
91
92 @Override
93 public void sendBroadcast(Intent intent, String receiverPermission) {
94 Log.d(TAG, "test context broadcasting " + intent);
95 if (CarStorageMonitoringManager.INTENT_EXCESSIVE_IO.equals(intent.getAction())) {
96 assertEquals(Car.PERMISSION_STORAGE_MONITORING, receiverPermission);
97
98 List<ResolveInfo> resolveInfoList = mContext.getPackageManager().
99 queryBroadcastReceivers(intent, 0);
100
101 assertEquals(1,
102 resolveInfoList.stream().map(ri -> ri.activityInfo)
103 .filter(Objects::nonNull)
104 .map(ai -> ai.name)
105 .filter(CarStorageMonitoringBroadcastReceiver.class
106 .getCanonicalName()::equals)
107 .count());
108
109 CarStorageMonitoringBroadcastReceiver.deliver(intent);
110 } else {
111 super.sendBroadcast(intent, receiverPermission);
112 }
113 }
114 }
115
Enrico Granata43024de2017-11-16 17:09:37 -0800116 static class ResourceOverrides {
117 private final HashMap<Integer, Integer> mIntegerOverrides = new HashMap<>();
118 private final HashMap<Integer, String> mStringOverrides = new HashMap<>();
119
120 void override(int id, int value) {
121 mIntegerOverrides.put(id, value);
122 }
123 void override(int id, String value) {
124 mStringOverrides.put(id, value);
125 }
126
127 void overrideResources(MockResources resources) {
128 mIntegerOverrides.forEach(resources::overrideResource);
129 mStringOverrides.forEach(resources::overrideResource);
130 }
131 }
132
Pavel Maltseved2c8642017-12-18 12:56:26 -0800133 private final Map<String, ResourceOverrides> PER_TEST_RESOURCES =
Enrico Granata43024de2017-11-16 17:09:37 -0800134 new HashMap<String, ResourceOverrides>() {
135 {
Enrico Granatae7db0002018-02-26 13:52:17 -0800136 put("testAggregateIoStats",
137 new ResourceOverrides() {{
138 override(R.integer.ioStatsNumSamplesToStore, 5);
139 }});
140 put("testIoStatsDeltas",
141 new ResourceOverrides() {{
142 override(R.integer.ioStatsNumSamplesToStore, 5);
143 }});
144 put("testEventDelivery",
145 new ResourceOverrides() {{
146 override(R.integer.ioStatsNumSamplesToStore, 5);
147 }});
Enrico Granata43024de2017-11-16 17:09:37 -0800148 put("testIntentOnExcessiveWrite",
149 new ResourceOverrides() {{
Enrico Granatae7db0002018-02-26 13:52:17 -0800150 override(R.integer.ioStatsNumSamplesToStore, 5);
Enrico Granata43024de2017-11-16 17:09:37 -0800151 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
152 override(R.integer.acceptableWrittenKBytesPerSample, 10);
153 override(R.integer.acceptableFsyncCallsPerSample, 1000);
154 override(R.string.intentReceiverForUnacceptableIoMetrics,
Pavel Maltseved2c8642017-12-18 12:56:26 -0800155 getFlattenComponent(
156 CarStorageMonitoringBroadcastReceiver.class));
Enrico Granata43024de2017-11-16 17:09:37 -0800157 }});
158
159 put("testIntentOnExcessiveFsync",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800160 new ResourceOverrides() {{
Enrico Granatae7db0002018-02-26 13:52:17 -0800161 override(R.integer.ioStatsNumSamplesToStore, 5);
Pavel Maltseved2c8642017-12-18 12:56:26 -0800162 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
163 override(R.integer.acceptableWrittenKBytesPerSample, 1000);
164 override(R.integer.acceptableFsyncCallsPerSample, 2);
165 override(R.string.intentReceiverForUnacceptableIoMetrics,
166 getFlattenComponent(
167 CarStorageMonitoringBroadcastReceiver.class));
168 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800169
170 put("testZeroWindowDisablesCollection",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800171 new ResourceOverrides() {{
172 override(R.integer.ioStatsNumSamplesToStore, 0);
173 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800174
Enrico Granata43024de2017-11-16 17:09:37 -0800175 }
176 };
177
Enrico Granataa97fce22017-10-27 14:57:34 -0700178 private static final class TestData {
179 static final TestData DEFAULT = new TestData(0, DEFAULT_WEAR_INFORMATION, null, null);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700180
181 final long uptime;
182 @NonNull
183 final WearInformation wearInformation;
184 @Nullable
185 final WearHistory wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700186 @NonNull
Enrico Granata7e0150d2017-11-06 17:20:17 -0800187 final UidIoRecord[] ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800188 @NonNull
189 final LifetimeWriteInfo[] previousLifetimeWriteInfo;
190 @NonNull
191 final LifetimeWriteInfo[] currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700192
Enrico Granataa97fce22017-10-27 14:57:34 -0700193 TestData(long uptime,
Enrico Granata1690a622018-01-22 17:34:46 -0800194 @Nullable WearInformation wearInformation,
195 @Nullable WearHistory wearHistory,
196 @Nullable UidIoRecord[] ioStats) {
197 this(uptime, wearInformation, wearHistory, ioStats, null, null);
198 }
199
200 TestData(long uptime,
Enrico Granataa97fce22017-10-27 14:57:34 -0700201 @Nullable WearInformation wearInformation,
202 @Nullable WearHistory wearHistory,
Enrico Granata1690a622018-01-22 17:34:46 -0800203 @Nullable UidIoRecord[] ioStats,
204 @Nullable LifetimeWriteInfo[] previousLifetimeWriteInfo,
205 @Nullable LifetimeWriteInfo[] currentLifetimeWriteInfo) {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700206 if (wearInformation == null) wearInformation = DEFAULT_WEAR_INFORMATION;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800207 if (ioStats == null) ioStats = new UidIoRecord[0];
Enrico Granata1690a622018-01-22 17:34:46 -0800208 if (previousLifetimeWriteInfo == null) {
209 previousLifetimeWriteInfo = new LifetimeWriteInfo[0];
210 }
211 if (currentLifetimeWriteInfo == null) {
212 currentLifetimeWriteInfo = new LifetimeWriteInfo[0];
213 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700214 this.uptime = uptime;
215 this.wearInformation = wearInformation;
216 this.wearHistory = wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700217 this.ioStats = ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800218 this.previousLifetimeWriteInfo = previousLifetimeWriteInfo;
219 this.currentLifetimeWriteInfo = currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700220 }
221 }
222
Enrico Granataa97fce22017-10-27 14:57:34 -0700223 private static final Map<String, TestData> PER_TEST_DATA =
Enrico Granata7e0150d2017-11-06 17:20:17 -0800224 new HashMap<String, TestData>() {
225 {
226 put("testReadWearHistory",
227 new TestData(6500, DEFAULT_WEAR_INFORMATION,
228 WearHistory.fromRecords(
229 WearEstimateRecord.Builder.newBuilder()
230 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
231 .toWearEstimate(new WearEstimate(10, 0))
232 .atUptime(1000)
233 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
234 WearEstimateRecord.Builder.newBuilder()
235 .fromWearEstimate(new WearEstimate(10, 0))
236 .toWearEstimate(new WearEstimate(20, 0))
237 .atUptime(4000)
238 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
239 WearEstimateRecord.Builder.newBuilder()
240 .fromWearEstimate(new WearEstimate(20, 0))
241 .toWearEstimate(new WearEstimate(30, 0))
242 .atUptime(6500)
243 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700244
Enrico Granata7e0150d2017-11-06 17:20:17 -0800245 put("testNotAcceptableWearEvent",
246 new TestData(2520006499L,
247 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
248 WearHistory.fromRecords(
249 WearEstimateRecord.Builder.newBuilder()
250 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
251 .toWearEstimate(new WearEstimate(10, 0))
252 .atUptime(1000)
253 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
254 WearEstimateRecord.Builder.newBuilder()
255 .fromWearEstimate(new WearEstimate(10, 0))
256 .toWearEstimate(new WearEstimate(20, 0))
257 .atUptime(4000)
258 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
259 WearEstimateRecord.Builder.newBuilder()
260 .fromWearEstimate(new WearEstimate(20, 0))
261 .toWearEstimate(new WearEstimate(30, 0))
262 .atUptime(6500)
263 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700264
Enrico Granata7e0150d2017-11-06 17:20:17 -0800265 put("testAcceptableWearEvent",
266 new TestData(2520006501L,
267 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
268 WearHistory.fromRecords(
269 WearEstimateRecord.Builder.newBuilder()
270 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
271 .toWearEstimate(new WearEstimate(10, 0))
272 .atUptime(1000)
273 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
274 WearEstimateRecord.Builder.newBuilder()
275 .fromWearEstimate(new WearEstimate(10, 0))
276 .toWearEstimate(new WearEstimate(20, 0))
277 .atUptime(4000)
278 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
279 WearEstimateRecord.Builder.newBuilder()
280 .fromWearEstimate(new WearEstimate(20, 0))
281 .toWearEstimate(new WearEstimate(30, 0))
282 .atUptime(6500)
283 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granataa97fce22017-10-27 14:57:34 -0700284
Enrico Granata7e0150d2017-11-06 17:20:17 -0800285 put("testBootIoStats",
286 new TestData(1000L,
287 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
288 null,
289 new UidIoRecord[]{
290 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
291 0, 0, 0, 0, 0),
292 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
293 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700294
Enrico Granata7e0150d2017-11-06 17:20:17 -0800295 put("testAggregateIoStats",
296 new TestData(1000L,
297 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
298 null,
299 new UidIoRecord[]{
300 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
301 0, 0, 0, 0, 0),
302 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
303 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700304
Enrico Granata7e0150d2017-11-06 17:20:17 -0800305 put("testIoStatsDeltas",
306 new TestData(1000L,
307 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
308 null,
309 new UidIoRecord[]{
310 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
311 0, 0, 0, 0, 0)}));
Enrico Granata1690a622018-01-22 17:34:46 -0800312
313 put("testComputeShutdownCost",
314 new TestData(1000L,
315 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
316 null,
317 null,
318 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
319 new LifetimeWriteInfo("p2", "ext4", 100),
320 new LifetimeWriteInfo("p3", "f2fs", 100)},
321 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
322 new LifetimeWriteInfo("p2", "ext4", 300),
323 new LifetimeWriteInfo("p3", "f2fs", 100)}));
324
325 put("testNegativeShutdownCost",
326 new TestData(1000L,
327 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
328 null,
329 null,
330 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
331 new LifetimeWriteInfo("p2", "ext4", 100),
332 new LifetimeWriteInfo("p3", "f2fs", 200)},
333 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
334 new LifetimeWriteInfo("p2", "ext4", 300),
335 new LifetimeWriteInfo("p3", "f2fs", 100)}));
Enrico Granata7e0150d2017-11-06 17:20:17 -0800336 }};
Enrico Granata1172f882017-09-21 14:51:30 -0700337
Enrico Granatab19bc322017-10-12 12:25:06 -0700338 private final MockSystemStateInterface mMockSystemStateInterface =
339 new MockSystemStateInterface();
340 private final MockStorageMonitoringInterface mMockStorageMonitoringInterface =
341 new MockStorageMonitoringInterface();
Enrico Granata0f72b742017-11-02 18:26:41 -0700342 private final MockTimeInterface mMockTimeInterface =
343 new MockTimeInterface();
Enrico Granata57738692018-02-23 15:35:07 -0800344 private TestContext mContext;
Enrico Granatab19bc322017-10-12 12:25:06 -0700345
Enrico Granata517a1e02017-09-20 16:15:50 -0700346 private CarStorageMonitoringManager mCarStorageMonitoringManager;
347
348 @Override
Enrico Granata57738692018-02-23 15:35:07 -0800349 protected MockContext getCarServiceContext() throws NameNotFoundException {
350 if (mContext == null) {
351 mContext = new TestContext(super.getCarServiceContext());
352 }
353 return mContext;
354 }
355
356 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700357 protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() {
358 SystemInterface.Builder builder = super.getSystemInterfaceBuilder();
359 return builder.withSystemStateInterface(mMockSystemStateInterface)
360 .withStorageMonitoringInterface(mMockStorageMonitoringInterface)
Enrico Granata0f72b742017-11-02 18:26:41 -0700361 .withTimeInterface(mMockTimeInterface);
Enrico Granatab19bc322017-10-12 12:25:06 -0700362 }
363
364 @Override
Enrico Granata517a1e02017-09-20 16:15:50 -0700365 protected synchronized void configureFakeSystemInterface() {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700366 try {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800367 final TestData wearData = PER_TEST_DATA.getOrDefault(getName(), TestData.DEFAULT);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700368 final WearHistory wearHistory = wearData.wearHistory;
369
Enrico Granatab19bc322017-10-12 12:25:06 -0700370 mMockStorageMonitoringInterface.setWearInformation(wearData.wearInformation);
Enrico Granata1690a622018-01-22 17:34:46 -0800371 mMockStorageMonitoringInterface.setWriteInfo(wearData.currentLifetimeWriteInfo);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700372
373 if (wearHistory != null) {
374 File wearHistoryFile = new File(getFakeSystemInterface().getFilesDir(),
375 CarStorageMonitoringService.WEAR_INFO_FILENAME);
376 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(wearHistoryFile))) {
377 wearHistory.writeToJson(jsonWriter);
378 }
379 }
380
381 if (wearData.uptime > 0) {
382 File uptimeFile = new File(getFakeSystemInterface().getFilesDir(),
Enrico Granatab19bc322017-10-12 12:25:06 -0700383 CarStorageMonitoringService.UPTIME_TRACKER_FILENAME);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700384 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(uptimeFile))) {
385 jsonWriter.beginObject();
386 jsonWriter.name("uptime").value(wearData.uptime);
387 jsonWriter.endObject();
388 }
389 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700390
Enrico Granata1690a622018-01-22 17:34:46 -0800391 if (wearData.previousLifetimeWriteInfo.length > 0) {
392 File previousLifetimeFile = new File(getFakeSystemInterface().getFilesDir(),
393 CarStorageMonitoringService.LIFETIME_WRITES_FILENAME);
394 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(previousLifetimeFile))) {
395 jsonWriter.beginObject();
396 jsonWriter.name("lifetimeWriteInfo").beginArray();
397 for (LifetimeWriteInfo writeInfo : wearData.previousLifetimeWriteInfo) {
398 writeInfo.writeToJson(jsonWriter);
399 }
400 jsonWriter.endArray().endObject();
401 }
402 }
403
Enrico Granataa97fce22017-10-27 14:57:34 -0700404 Arrays.stream(wearData.ioStats).forEach(
405 mMockStorageMonitoringInterface::addIoStatsRecord);
406
Enrico Granata286cd8e2017-09-25 14:46:49 -0700407 } catch (IOException e) {
408 Log.e(TAG, "failed to configure fake system interface", e);
409 fail("failed to configure fake system interface instance");
410 }
Enrico Granata43024de2017-11-16 17:09:37 -0800411 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700412
Enrico Granata43024de2017-11-16 17:09:37 -0800413 @Override
414 protected synchronized void configureResourceOverrides(MockResources resources) {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800415 final ResourceOverrides overrides = PER_TEST_RESOURCES.getOrDefault(getName(), null);
Enrico Granata43024de2017-11-16 17:09:37 -0800416 if (overrides != null) {
417 overrides.overrideResources(resources);
418 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700419 }
420
421 @Override
Pavel Maltseved2c8642017-12-18 12:56:26 -0800422 public void setUp() throws Exception {
Enrico Granata517a1e02017-09-20 16:15:50 -0700423 super.setUp();
Enrico Granatab19bc322017-10-12 12:25:06 -0700424 mMockSystemStateInterface.executeBootCompletedActions();
Enrico Granatacf53fd72017-09-28 10:45:44 -0700425
Enrico Granata517a1e02017-09-20 16:15:50 -0700426 mCarStorageMonitoringManager =
427 (CarStorageMonitoringManager) getCar().getCarManager(Car.STORAGE_MONITORING_SERVICE);
428 }
429
Pavel Maltseved2c8642017-12-18 12:56:26 -0800430 @Test
Enrico Granata517a1e02017-09-20 16:15:50 -0700431 public void testReadPreEolInformation() throws Exception {
Enrico Granata1172f882017-09-21 14:51:30 -0700432 assertEquals(DEFAULT_WEAR_INFORMATION.preEolInfo,
Enrico Granata517a1e02017-09-20 16:15:50 -0700433 mCarStorageMonitoringManager.getPreEolIndicatorStatus());
434 }
Enrico Granata1172f882017-09-21 14:51:30 -0700435
Pavel Maltseved2c8642017-12-18 12:56:26 -0800436 @Test
Enrico Granata1172f882017-09-21 14:51:30 -0700437 public void testReadWearEstimate() throws Exception {
438 final WearEstimate wearEstimate = mCarStorageMonitoringManager.getWearEstimate();
439
440 assertNotNull(wearEstimate);
441 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateA, wearEstimate.typeA);
442 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateB, wearEstimate.typeB);
443 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700444
Pavel Maltseved2c8642017-12-18 12:56:26 -0800445 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700446 public void testReadWearHistory() throws Exception {
447 final List<WearEstimateChange> wearEstimateChanges =
448 mCarStorageMonitoringManager.getWearEstimateHistory();
449
450 assertNotNull(wearEstimateChanges);
451 assertFalse(wearEstimateChanges.isEmpty());
452
Enrico Granataa97fce22017-10-27 14:57:34 -0700453 final WearHistory expectedWearHistory = PER_TEST_DATA.get(getName()).wearHistory;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700454
455 assertEquals(expectedWearHistory.size(), wearEstimateChanges.size());
456 for (int i = 0; i < wearEstimateChanges.size(); ++i) {
457 final WearEstimateRecord expected = expectedWearHistory.get(i);
458 final WearEstimateChange actual = wearEstimateChanges.get(i);
459
460 assertTrue(expected.isSameAs(actual));
461 }
462 }
463
464 private void checkLastWearEvent(boolean isAcceptable) throws Exception {
465 final List<WearEstimateChange> wearEstimateChanges =
466 mCarStorageMonitoringManager.getWearEstimateHistory();
467
468 assertNotNull(wearEstimateChanges);
469 assertFalse(wearEstimateChanges.isEmpty());
470
Enrico Granataa97fce22017-10-27 14:57:34 -0700471 final TestData wearData = PER_TEST_DATA.get(getName());
Enrico Granata286cd8e2017-09-25 14:46:49 -0700472
473 final WearInformation expectedCurrentWear = wearData.wearInformation;
474 final WearEstimate expectedPreviousWear = wearData.wearHistory.getLast().getNewWearEstimate();
475
476 final WearEstimateChange actualCurrentWear =
477 wearEstimateChanges.get(wearEstimateChanges.size() - 1);
478
479 assertEquals(isAcceptable, actualCurrentWear.isAcceptableDegradation);
480 assertEquals(expectedCurrentWear.toWearEstimate(), actualCurrentWear.newEstimate);
481 assertEquals(expectedPreviousWear, actualCurrentWear.oldEstimate);
482 }
483
Pavel Maltseved2c8642017-12-18 12:56:26 -0800484 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700485 public void testNotAcceptableWearEvent() throws Exception {
486 checkLastWearEvent(false);
487 }
488
Pavel Maltseved2c8642017-12-18 12:56:26 -0800489 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700490 public void testAcceptableWearEvent() throws Exception {
491 checkLastWearEvent(true);
492 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700493
Pavel Maltseved2c8642017-12-18 12:56:26 -0800494 @Test
Enrico Granataa97fce22017-10-27 14:57:34 -0700495 public void testBootIoStats() throws Exception {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800496 final List<IoStatsEntry> bootIoStats =
Enrico Granataa97fce22017-10-27 14:57:34 -0700497 mCarStorageMonitoringManager.getBootIoStats();
498
499 assertNotNull(bootIoStats);
500 assertFalse(bootIoStats.isEmpty());
501
Enrico Granata7e0150d2017-11-06 17:20:17 -0800502 final UidIoRecord[] bootIoRecords = PER_TEST_DATA.get(getName()).ioStats;
Enrico Granataa97fce22017-10-27 14:57:34 -0700503
504 bootIoStats.forEach(uidIoStats -> assertTrue(Arrays.stream(bootIoRecords).anyMatch(
505 ioRecord -> uidIoStats.representsSameMetrics(ioRecord))));
506 }
507
Pavel Maltseved2c8642017-12-18 12:56:26 -0800508 @Test
Enrico Granata0f72b742017-11-02 18:26:41 -0700509 public void testAggregateIoStats() throws Exception {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800510 UidIoRecord oldRecord1000 = mMockStorageMonitoringInterface.getIoStatsRecord(1000);
Enrico Granata0f72b742017-11-02 18:26:41 -0700511
Enrico Granata7e0150d2017-11-06 17:20:17 -0800512 UidIoRecord newRecord1000 = new UidIoRecord(1000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700513 oldRecord1000.foreground_rchar,
514 oldRecord1000.foreground_wchar + 50,
515 oldRecord1000.foreground_read_bytes,
516 oldRecord1000.foreground_write_bytes + 100,
517 oldRecord1000.foreground_fsync + 1,
518 oldRecord1000.background_rchar,
519 oldRecord1000.background_wchar,
520 oldRecord1000.background_read_bytes,
521 oldRecord1000.background_write_bytes,
522 oldRecord1000.background_fsync);
523
524 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord1000);
525
Enrico Granata7e0150d2017-11-06 17:20:17 -0800526 UidIoRecord record2000 = new UidIoRecord(2000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700527 1024,
528 2048,
529 0,
530 1024,
531 1,
532 0,
533 0,
534 0,
535 0,
536 0);
537
538 mMockStorageMonitoringInterface.addIoStatsRecord(record2000);
539
540 mMockTimeInterface.tick();
541
Enrico Granatadbda56f2017-12-18 11:53:22 -0800542 List<IoStatsEntry> aggregateIoStats = mCarStorageMonitoringManager.getAggregateIoStats();
Enrico Granata0f72b742017-11-02 18:26:41 -0700543
544 assertNotNull(aggregateIoStats);
545 assertFalse(aggregateIoStats.isEmpty());
546
547 aggregateIoStats.forEach(serviceIoStat -> {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800548 UidIoRecord mockIoStat = mMockStorageMonitoringInterface.getIoStatsRecord(
Enrico Granata0f72b742017-11-02 18:26:41 -0700549 serviceIoStat.uid);
550
551 assertNotNull(mockIoStat);
552
553 assertTrue(serviceIoStat.representsSameMetrics(mockIoStat));
554 });
555 }
556
Pavel Maltseved2c8642017-12-18 12:56:26 -0800557 @Test
Enrico Granata7e0150d2017-11-06 17:20:17 -0800558 public void testIoStatsDeltas() throws Exception {
559 UidIoRecord oldRecord0 = mMockStorageMonitoringInterface.getIoStatsRecord(0);
560
561 UidIoRecord newRecord0 = new UidIoRecord(0,
562 oldRecord0.foreground_rchar,
563 oldRecord0.foreground_wchar + 100,
564 oldRecord0.foreground_read_bytes,
565 oldRecord0.foreground_write_bytes + 50,
566 oldRecord0.foreground_fsync,
567 oldRecord0.background_rchar,
568 oldRecord0.background_wchar,
569 oldRecord0.background_read_bytes + 100,
570 oldRecord0.background_write_bytes,
571 oldRecord0.background_fsync);
572
573 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord0);
574 mMockTimeInterface.setUptime(500).tick();
575
Enrico Granatadbda56f2017-12-18 11:53:22 -0800576 List<IoStats> deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800577 assertNotNull(deltas);
578 assertEquals(1, deltas.size());
579
Enrico Granatadbda56f2017-12-18 11:53:22 -0800580 IoStats delta0 = deltas.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800581 assertNotNull(delta0);
582 assertEquals(500, delta0.getTimestamp());
583
Enrico Granatadbda56f2017-12-18 11:53:22 -0800584 List<IoStatsEntry> delta0Stats = delta0.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800585 assertNotNull(delta0Stats);
586 assertEquals(1, delta0Stats.size());
587
Enrico Granatadbda56f2017-12-18 11:53:22 -0800588 IoStatsEntry deltaRecord0 = delta0Stats.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800589
590 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
591
592 UidIoRecord newerRecord0 = new UidIoRecord(0,
593 newRecord0.foreground_rchar + 200,
594 newRecord0.foreground_wchar + 10,
595 newRecord0.foreground_read_bytes,
596 newRecord0.foreground_write_bytes,
597 newRecord0.foreground_fsync,
598 newRecord0.background_rchar,
599 newRecord0.background_wchar + 100,
600 newRecord0.background_read_bytes,
601 newRecord0.background_write_bytes + 30,
602 newRecord0.background_fsync + 2);
603
604 mMockStorageMonitoringInterface.addIoStatsRecord(newerRecord0);
605 mMockTimeInterface.setUptime(1000).tick();
606
607 deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
608 assertNotNull(deltas);
609 assertEquals(2, deltas.size());
610
611 delta0 = deltas.get(0);
612 assertNotNull(delta0);
613 assertEquals(500, delta0.getTimestamp());
614
615 delta0Stats = delta0.getStats();
616 assertNotNull(delta0Stats);
617 assertEquals(1, delta0Stats.size());
618
619 deltaRecord0 = delta0Stats.get(0);
620
621 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
622
Enrico Granatadbda56f2017-12-18 11:53:22 -0800623 IoStats delta1 = deltas.get(1);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800624 assertNotNull(delta1);
625 assertEquals(1000, delta1.getTimestamp());
626
Enrico Granatadbda56f2017-12-18 11:53:22 -0800627 List<IoStatsEntry> delta1Stats = delta1.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800628 assertNotNull(delta1Stats);
629 assertEquals(1, delta1Stats.size());
630
631 deltaRecord0 = delta1Stats.get(0);
632
633 assertTrue(deltaRecord0.representsSameMetrics(newerRecord0.delta(newRecord0)));
634 }
635
Pavel Maltseved2c8642017-12-18 12:56:26 -0800636 @Test
Enrico Granata7dce3792017-11-09 14:13:28 -0800637 public void testEventDelivery() throws Exception {
638 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
639
640 UidIoRecord record = new UidIoRecord(0,
641 0,
642 100,
643 0,
644 75,
645 1,
646 0,
647 0,
648 0,
649 0,
650 0);
651
652 Listener listener1 = new Listener("listener1");
653 Listener listener2 = new Listener("listener2");
654
655 mCarStorageMonitoringManager.registerListener(listener1);
656 mCarStorageMonitoringManager.registerListener(listener2);
657
658 mMockStorageMonitoringInterface.addIoStatsRecord(record);
659 mMockTimeInterface.setUptime(500).tick();
660
661 assertTrue(listener1.waitForEvent(eventDeliveryDeadline));
662 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
663
Enrico Granatadbda56f2017-12-18 11:53:22 -0800664 IoStats event1 = listener1.reset();
665 IoStats event2 = listener2.reset();
Enrico Granata7dce3792017-11-09 14:13:28 -0800666
667 assertEquals(event1, event2);
668 event1.getStats().forEach(stats -> assertTrue(stats.representsSameMetrics(record)));
669
670 mCarStorageMonitoringManager.unregisterListener(listener1);
671
672 mMockTimeInterface.setUptime(600).tick();
673 assertFalse(listener1.waitForEvent(eventDeliveryDeadline));
674 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
675 }
676
Pavel Maltseved2c8642017-12-18 12:56:26 -0800677 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800678 public void testIntentOnExcessiveWrite() throws Exception {
679 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
680
681 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
682
683 UidIoRecord record = new UidIoRecord(0,
684 0,
685 5120,
686 0,
687 5000,
688 1,
689 0,
690 7168,
691 0,
692 7000,
693 0);
694
695 mMockStorageMonitoringInterface.addIoStatsRecord(record);
696 mMockTimeInterface.setUptime(500).tick();
697
698 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
699 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
700 assertNotNull(deliveredIntent);
701 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
702 }
703
Pavel Maltseved2c8642017-12-18 12:56:26 -0800704 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800705 public void testIntentOnExcessiveFsync() throws Exception {
706 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
707
708 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
709
710 UidIoRecord record = new UidIoRecord(0,
711 0,
712 0,
713 0,
714 0,
715 2,
716 0,
717 0,
718 0,
719 0,
720 3);
721
722 mMockStorageMonitoringInterface.addIoStatsRecord(record);
723 mMockTimeInterface.setUptime(500).tick();
724
725 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
726 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
727 assertNotNull(deliveredIntent);
728 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
729 }
730
Pavel Maltseved2c8642017-12-18 12:56:26 -0800731 @Test
Enrico Granata88d92c82017-11-30 16:47:15 -0800732 public void testZeroWindowDisablesCollection() throws Exception {
733 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
734
735 UidIoRecord record = new UidIoRecord(0,
736 0,
737 100,
738 0,
739 75,
740 1,
741 0,
742 0,
743 0,
744 0,
745 0);
746
747 Listener listener = new Listener("listener");
748
749 mMockStorageMonitoringInterface.addIoStatsRecord(record);
750 mMockTimeInterface.setUptime(500).tick();
751
752 assertFalse(listener.waitForEvent(eventDeliveryDeadline));
753
754 assertEquals(0, mCarStorageMonitoringManager.getIoStatsDeltas().size());
755 }
756
Enrico Granata1690a622018-01-22 17:34:46 -0800757 @Test
758 public void testComputeShutdownCost() throws Exception {
759 assertEquals(280, mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
760 }
761
762 @Test
763 public void testNegativeShutdownCost() throws Exception {
764 assertEquals(CarStorageMonitoringManager.SHUTDOWN_COST_INFO_MISSING,
765 mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
766 }
767
Pavel Maltseved2c8642017-12-18 12:56:26 -0800768 private String getName() {
769 return mTestName.getMethodName();
770 }
771
Enrico Granatadbda56f2017-12-18 11:53:22 -0800772 static final class Listener implements CarStorageMonitoringManager.IoStatsListener {
Enrico Granata7dce3792017-11-09 14:13:28 -0800773 private final String mName;
774 private final Object mSync = new Object();
775
Enrico Granatadbda56f2017-12-18 11:53:22 -0800776 private IoStats mLastEvent = null;
Enrico Granata7dce3792017-11-09 14:13:28 -0800777
778 Listener(String name) {
779 mName = name;
780 }
781
Enrico Granatadbda56f2017-12-18 11:53:22 -0800782 IoStats reset() {
Enrico Granata7dce3792017-11-09 14:13:28 -0800783 synchronized (mSync) {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800784 IoStats lastEvent = mLastEvent;
Enrico Granata7dce3792017-11-09 14:13:28 -0800785 mLastEvent = null;
786 return lastEvent;
787 }
788 }
789
790 boolean waitForEvent(Duration duration) {
791 long start = SystemClock.elapsedRealtime();
792 long end = start + duration.toMillis();
793 synchronized (mSync) {
794 while (mLastEvent == null && SystemClock.elapsedRealtime() < end) {
795 try {
796 mSync.wait(10L);
797 } catch (InterruptedException e) {
798 // ignore
799 }
800 }
801 }
802
803 return (mLastEvent != null);
804 }
805
806 @Override
Enrico Granatadbda56f2017-12-18 11:53:22 -0800807 public void onSnapshot(IoStats event) {
Enrico Granata7dce3792017-11-09 14:13:28 -0800808 synchronized (mSync) {
809 Log.d(TAG, "listener " + mName + " received event " + event);
810 // We're going to hold a reference to this object
811 mLastEvent = event;
812 mSync.notify();
813 }
814 }
815
816 }
817
Enrico Granatab19bc322017-10-12 12:25:06 -0700818 static final class MockStorageMonitoringInterface implements StorageMonitoringInterface,
819 WearInformationProvider {
820 private WearInformation mWearInformation = null;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800821 private SparseArray<UidIoRecord> mIoStats = new SparseArray<>();
Enrico Granataa97fce22017-10-27 14:57:34 -0700822 private UidIoStatsProvider mIoStatsProvider = () -> mIoStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800823 private LifetimeWriteInfo[] mWriteInfo = new LifetimeWriteInfo[0];
Enrico Granatab19bc322017-10-12 12:25:06 -0700824
825 void setWearInformation(WearInformation wearInformation) {
826 mWearInformation = wearInformation;
827 }
828
Enrico Granata1690a622018-01-22 17:34:46 -0800829 void setWriteInfo(LifetimeWriteInfo[] writeInfo) {
830 mWriteInfo = writeInfo;
831 }
832
Enrico Granata7e0150d2017-11-06 17:20:17 -0800833 void addIoStatsRecord(UidIoRecord record) {
Enrico Granataa97fce22017-10-27 14:57:34 -0700834 mIoStats.append(record.uid, record);
835 }
836
Enrico Granata7e0150d2017-11-06 17:20:17 -0800837 UidIoRecord getIoStatsRecord(int uid) {
Enrico Granata0f72b742017-11-02 18:26:41 -0700838 return mIoStats.get(uid);
839 }
840
Enrico Granataa97fce22017-10-27 14:57:34 -0700841 void deleteIoStatsRecord(int uid) {
842 mIoStats.delete(uid);
843 }
844
Enrico Granatab19bc322017-10-12 12:25:06 -0700845 @Override
846 public WearInformation load() {
847 return mWearInformation;
848 }
849
850 @Override
Enrico Granata1690a622018-01-22 17:34:46 -0800851 public LifetimeWriteInfoProvider getLifetimeWriteInfoProvider() {
852 // cannot make this directly implement because Java does not allow
853 // overloading based on return type and there already is a method named
854 // load() in WearInformationProvider
855 return new LifetimeWriteInfoProvider() {
856 @Override
857 public LifetimeWriteInfo[] load() {
858 return mWriteInfo;
859 }
860 };
861 }
862
863 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700864 public WearInformationProvider[] getFlashWearInformationProviders() {
865 return new WearInformationProvider[] {this};
866 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700867
868 @Override
869 public UidIoStatsProvider getUidIoStatsProvider() {
870 return mIoStatsProvider;
871 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700872 }
873
874 static final class MockTimeInterface implements TimeInterface {
Enrico Granata0f72b742017-11-02 18:26:41 -0700875 private final List<Pair<Runnable, Long>> mActionsList = new ArrayList<>();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800876 private long mUptime = 0;
Enrico Granatab19bc322017-10-12 12:25:06 -0700877
878 @Override
879 public long getUptime(boolean includeDeepSleepTime) {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800880 return mUptime;
Enrico Granatab19bc322017-10-12 12:25:06 -0700881 }
882
883 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700884 public void scheduleAction(Runnable r, long delayMs) {
885 mActionsList.add(Pair.create(r, delayMs));
886 mActionsList.sort(Comparator.comparing(d -> d.second));
887 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700888
889 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700890 public void cancelAllActions() {
891 mActionsList.clear();
892 }
893
894 void tick() {
895 mActionsList.forEach(pair -> pair.first.run());
896 }
Enrico Granata7e0150d2017-11-06 17:20:17 -0800897
898 MockTimeInterface setUptime(long time) {
899 mUptime = time;
900 return this;
901 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700902 }
903
904 static final class MockSystemStateInterface implements SystemStateInterface {
905 private final List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>();
906
907 @Override
908 public void shutdown() {}
909
910 @Override
Steve Paik07db5ed2018-09-24 16:48:52 -0700911 public boolean enterDeepSleep() {
Steve Paik0f9fc002018-02-09 17:42:00 -0800912 return true;
913 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700914
915 @Override
916 public void scheduleActionForBootCompleted(Runnable action, Duration delay) {
917 mActionsList.add(Pair.create(action, delay));
918 mActionsList.sort(Comparator.comparing(d -> d.second));
919 }
920
921 void executeBootCompletedActions() {
922 for (Pair<Runnable, Duration> action : mActionsList) {
923 action.first.run();
924 }
925 }
926 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700927}