blob: 115700799f98ea2b66af6914dd02e92c0581ed2d [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 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
Enrico Granata1690a622018-01-22 17:34:46 -080058import com.android.car.test.utils.TemporaryFile;
Enrico Granata57738692018-02-23 15:35:07 -080059import java.util.ArrayDeque;
Enrico Granata1690a622018-01-22 17:34:46 -080060import java.util.Collection;
Enrico Granata57738692018-02-23 15:35:07 -080061import java.util.Objects;
62import java.util.Queue;
Enrico Granata1690a622018-01-22 17:34:46 -080063import org.json.JSONArray;
64import org.json.JSONObject;
Pavel Maltseved2c8642017-12-18 12:56:26 -080065import org.junit.Rule;
66import org.junit.Test;
67import org.junit.rules.TestName;
68import org.junit.runner.RunWith;
69
Enrico Granata286cd8e2017-09-25 14:46:49 -070070import java.io.File;
71import java.io.FileWriter;
72import java.io.IOException;
Enrico Granatab19bc322017-10-12 12:25:06 -070073import java.time.Duration;
Enrico Granata286cd8e2017-09-25 14:46:49 -070074import java.time.Instant;
Enrico Granatab19bc322017-10-12 12:25:06 -070075import java.util.ArrayList;
Enrico Granataa97fce22017-10-27 14:57:34 -070076import java.util.Arrays;
Enrico Granatab19bc322017-10-12 12:25:06 -070077import java.util.Comparator;
Enrico Granata286cd8e2017-09-25 14:46:49 -070078import java.util.HashMap;
79import java.util.List;
80import java.util.Map;
Enrico Granata517a1e02017-09-20 16:15:50 -070081
82/** Test the public entry points for the CarStorageMonitoringManager */
Pavel Maltseved2c8642017-12-18 12:56:26 -080083@RunWith(AndroidJUnit4.class)
Enrico Granata517a1e02017-09-20 16:15:50 -070084@MediumTest
85public class CarStorageMonitoringTest extends MockedCarTestBase {
86 private static final String TAG = CarStorageMonitoringTest.class.getSimpleName();
87
Pavel Maltseved2c8642017-12-18 12:56:26 -080088 @Rule public TestName mTestName = new TestName();
89
Enrico Granata1172f882017-09-21 14:51:30 -070090 private static final WearInformation DEFAULT_WEAR_INFORMATION =
Enrico Granata286cd8e2017-09-25 14:46:49 -070091 new WearInformation(30, 0, WearInformation.PRE_EOL_INFO_NORMAL);
92
Enrico Granata57738692018-02-23 15:35:07 -080093 final class TestContext extends MockContext {
94 TestContext(MockContext context) {
95 super(context.getBaseContext());
96 }
97
98 @Override
99 public void sendBroadcast(Intent intent, String receiverPermission) {
100 Log.d(TAG, "test context broadcasting " + intent);
101 if (CarStorageMonitoringManager.INTENT_EXCESSIVE_IO.equals(intent.getAction())) {
102 assertEquals(Car.PERMISSION_STORAGE_MONITORING, receiverPermission);
103
104 List<ResolveInfo> resolveInfoList = mContext.getPackageManager().
105 queryBroadcastReceivers(intent, 0);
106
107 assertEquals(1,
108 resolveInfoList.stream().map(ri -> ri.activityInfo)
109 .filter(Objects::nonNull)
110 .map(ai -> ai.name)
111 .filter(CarStorageMonitoringBroadcastReceiver.class
112 .getCanonicalName()::equals)
113 .count());
114
115 CarStorageMonitoringBroadcastReceiver.deliver(intent);
116 } else {
117 super.sendBroadcast(intent, receiverPermission);
118 }
119 }
120 }
121
Enrico Granata43024de2017-11-16 17:09:37 -0800122 static class ResourceOverrides {
123 private final HashMap<Integer, Integer> mIntegerOverrides = new HashMap<>();
124 private final HashMap<Integer, String> mStringOverrides = new HashMap<>();
125
126 void override(int id, int value) {
127 mIntegerOverrides.put(id, value);
128 }
129 void override(int id, String value) {
130 mStringOverrides.put(id, value);
131 }
132
133 void overrideResources(MockResources resources) {
134 mIntegerOverrides.forEach(resources::overrideResource);
135 mStringOverrides.forEach(resources::overrideResource);
136 }
137 }
138
Pavel Maltseved2c8642017-12-18 12:56:26 -0800139 private final Map<String, ResourceOverrides> PER_TEST_RESOURCES =
Enrico Granata43024de2017-11-16 17:09:37 -0800140 new HashMap<String, ResourceOverrides>() {
141 {
Enrico Granatae7db0002018-02-26 13:52:17 -0800142 put("testAggregateIoStats",
143 new ResourceOverrides() {{
144 override(R.integer.ioStatsNumSamplesToStore, 5);
145 }});
146 put("testIoStatsDeltas",
147 new ResourceOverrides() {{
148 override(R.integer.ioStatsNumSamplesToStore, 5);
149 }});
150 put("testEventDelivery",
151 new ResourceOverrides() {{
152 override(R.integer.ioStatsNumSamplesToStore, 5);
153 }});
Enrico Granata43024de2017-11-16 17:09:37 -0800154 put("testIntentOnExcessiveWrite",
155 new ResourceOverrides() {{
Enrico Granatae7db0002018-02-26 13:52:17 -0800156 override(R.integer.ioStatsNumSamplesToStore, 5);
Enrico Granata43024de2017-11-16 17:09:37 -0800157 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
158 override(R.integer.acceptableWrittenKBytesPerSample, 10);
159 override(R.integer.acceptableFsyncCallsPerSample, 1000);
160 override(R.string.intentReceiverForUnacceptableIoMetrics,
Pavel Maltseved2c8642017-12-18 12:56:26 -0800161 getFlattenComponent(
162 CarStorageMonitoringBroadcastReceiver.class));
Enrico Granata43024de2017-11-16 17:09:37 -0800163 }});
164
165 put("testIntentOnExcessiveFsync",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800166 new ResourceOverrides() {{
Enrico Granatae7db0002018-02-26 13:52:17 -0800167 override(R.integer.ioStatsNumSamplesToStore, 5);
Pavel Maltseved2c8642017-12-18 12:56:26 -0800168 override(R.integer.maxExcessiveIoSamplesInWindow, 0);
169 override(R.integer.acceptableWrittenKBytesPerSample, 1000);
170 override(R.integer.acceptableFsyncCallsPerSample, 2);
171 override(R.string.intentReceiverForUnacceptableIoMetrics,
172 getFlattenComponent(
173 CarStorageMonitoringBroadcastReceiver.class));
174 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800175
176 put("testZeroWindowDisablesCollection",
Pavel Maltseved2c8642017-12-18 12:56:26 -0800177 new ResourceOverrides() {{
178 override(R.integer.ioStatsNumSamplesToStore, 0);
179 }});
Enrico Granata88d92c82017-11-30 16:47:15 -0800180
Enrico Granata43024de2017-11-16 17:09:37 -0800181 }
182 };
183
Enrico Granataa97fce22017-10-27 14:57:34 -0700184 private static final class TestData {
185 static final TestData DEFAULT = new TestData(0, DEFAULT_WEAR_INFORMATION, null, null);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700186
187 final long uptime;
188 @NonNull
189 final WearInformation wearInformation;
190 @Nullable
191 final WearHistory wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700192 @NonNull
Enrico Granata7e0150d2017-11-06 17:20:17 -0800193 final UidIoRecord[] ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800194 @NonNull
195 final LifetimeWriteInfo[] previousLifetimeWriteInfo;
196 @NonNull
197 final LifetimeWriteInfo[] currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700198
Enrico Granataa97fce22017-10-27 14:57:34 -0700199 TestData(long uptime,
Enrico Granata1690a622018-01-22 17:34:46 -0800200 @Nullable WearInformation wearInformation,
201 @Nullable WearHistory wearHistory,
202 @Nullable UidIoRecord[] ioStats) {
203 this(uptime, wearInformation, wearHistory, ioStats, null, null);
204 }
205
206 TestData(long uptime,
Enrico Granataa97fce22017-10-27 14:57:34 -0700207 @Nullable WearInformation wearInformation,
208 @Nullable WearHistory wearHistory,
Enrico Granata1690a622018-01-22 17:34:46 -0800209 @Nullable UidIoRecord[] ioStats,
210 @Nullable LifetimeWriteInfo[] previousLifetimeWriteInfo,
211 @Nullable LifetimeWriteInfo[] currentLifetimeWriteInfo) {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700212 if (wearInformation == null) wearInformation = DEFAULT_WEAR_INFORMATION;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800213 if (ioStats == null) ioStats = new UidIoRecord[0];
Enrico Granata1690a622018-01-22 17:34:46 -0800214 if (previousLifetimeWriteInfo == null) {
215 previousLifetimeWriteInfo = new LifetimeWriteInfo[0];
216 }
217 if (currentLifetimeWriteInfo == null) {
218 currentLifetimeWriteInfo = new LifetimeWriteInfo[0];
219 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700220 this.uptime = uptime;
221 this.wearInformation = wearInformation;
222 this.wearHistory = wearHistory;
Enrico Granataa97fce22017-10-27 14:57:34 -0700223 this.ioStats = ioStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800224 this.previousLifetimeWriteInfo = previousLifetimeWriteInfo;
225 this.currentLifetimeWriteInfo = currentLifetimeWriteInfo;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700226 }
227 }
228
Enrico Granataa97fce22017-10-27 14:57:34 -0700229 private static final Map<String, TestData> PER_TEST_DATA =
Enrico Granata7e0150d2017-11-06 17:20:17 -0800230 new HashMap<String, TestData>() {
231 {
232 put("testReadWearHistory",
233 new TestData(6500, DEFAULT_WEAR_INFORMATION,
234 WearHistory.fromRecords(
235 WearEstimateRecord.Builder.newBuilder()
236 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
237 .toWearEstimate(new WearEstimate(10, 0))
238 .atUptime(1000)
239 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
240 WearEstimateRecord.Builder.newBuilder()
241 .fromWearEstimate(new WearEstimate(10, 0))
242 .toWearEstimate(new WearEstimate(20, 0))
243 .atUptime(4000)
244 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
245 WearEstimateRecord.Builder.newBuilder()
246 .fromWearEstimate(new WearEstimate(20, 0))
247 .toWearEstimate(new WearEstimate(30, 0))
248 .atUptime(6500)
249 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700250
Enrico Granata7e0150d2017-11-06 17:20:17 -0800251 put("testNotAcceptableWearEvent",
252 new TestData(2520006499L,
253 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
254 WearHistory.fromRecords(
255 WearEstimateRecord.Builder.newBuilder()
256 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
257 .toWearEstimate(new WearEstimate(10, 0))
258 .atUptime(1000)
259 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
260 WearEstimateRecord.Builder.newBuilder()
261 .fromWearEstimate(new WearEstimate(10, 0))
262 .toWearEstimate(new WearEstimate(20, 0))
263 .atUptime(4000)
264 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
265 WearEstimateRecord.Builder.newBuilder()
266 .fromWearEstimate(new WearEstimate(20, 0))
267 .toWearEstimate(new WearEstimate(30, 0))
268 .atUptime(6500)
269 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granata286cd8e2017-09-25 14:46:49 -0700270
Enrico Granata7e0150d2017-11-06 17:20:17 -0800271 put("testAcceptableWearEvent",
272 new TestData(2520006501L,
273 new WearInformation(40, 0, WearInformation.PRE_EOL_INFO_NORMAL),
274 WearHistory.fromRecords(
275 WearEstimateRecord.Builder.newBuilder()
276 .fromWearEstimate(WearEstimate.UNKNOWN_ESTIMATE)
277 .toWearEstimate(new WearEstimate(10, 0))
278 .atUptime(1000)
279 .atTimestamp(Instant.ofEpochMilli(5000)).build(),
280 WearEstimateRecord.Builder.newBuilder()
281 .fromWearEstimate(new WearEstimate(10, 0))
282 .toWearEstimate(new WearEstimate(20, 0))
283 .atUptime(4000)
284 .atTimestamp(Instant.ofEpochMilli(12000)).build(),
285 WearEstimateRecord.Builder.newBuilder()
286 .fromWearEstimate(new WearEstimate(20, 0))
287 .toWearEstimate(new WearEstimate(30, 0))
288 .atUptime(6500)
289 .atTimestamp(Instant.ofEpochMilli(17000)).build()), null));
Enrico Granataa97fce22017-10-27 14:57:34 -0700290
Enrico Granata7e0150d2017-11-06 17:20:17 -0800291 put("testBootIoStats",
292 new TestData(1000L,
293 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
294 null,
295 new UidIoRecord[]{
296 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
297 0, 0, 0, 0, 0),
298 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
299 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700300
Enrico Granata7e0150d2017-11-06 17:20:17 -0800301 put("testAggregateIoStats",
302 new TestData(1000L,
303 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
304 null,
305 new UidIoRecord[]{
306 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
307 0, 0, 0, 0, 0),
308 new UidIoRecord(1000, 200, 5000, 0, 4000, 0,
309 1000, 0, 500, 0, 0)}));
Enrico Granata0f72b742017-11-02 18:26:41 -0700310
Enrico Granata7e0150d2017-11-06 17:20:17 -0800311 put("testIoStatsDeltas",
312 new TestData(1000L,
313 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
314 null,
315 new UidIoRecord[]{
316 new UidIoRecord(0, 5000, 6000, 3000, 1000, 1,
317 0, 0, 0, 0, 0)}));
Enrico Granata1690a622018-01-22 17:34:46 -0800318
319 put("testComputeShutdownCost",
320 new TestData(1000L,
321 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
322 null,
323 null,
324 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
325 new LifetimeWriteInfo("p2", "ext4", 100),
326 new LifetimeWriteInfo("p3", "f2fs", 100)},
327 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
328 new LifetimeWriteInfo("p2", "ext4", 300),
329 new LifetimeWriteInfo("p3", "f2fs", 100)}));
330
331 put("testNegativeShutdownCost",
332 new TestData(1000L,
333 new WearInformation(0, 0, WearInformation.PRE_EOL_INFO_NORMAL),
334 null,
335 null,
336 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 120),
337 new LifetimeWriteInfo("p2", "ext4", 100),
338 new LifetimeWriteInfo("p3", "f2fs", 200)},
339 new LifetimeWriteInfo[] { new LifetimeWriteInfo("p1", "ext4", 200),
340 new LifetimeWriteInfo("p2", "ext4", 300),
341 new LifetimeWriteInfo("p3", "f2fs", 100)}));
Enrico Granata7e0150d2017-11-06 17:20:17 -0800342 }};
Enrico Granata1172f882017-09-21 14:51:30 -0700343
Enrico Granatab19bc322017-10-12 12:25:06 -0700344 private final MockSystemStateInterface mMockSystemStateInterface =
345 new MockSystemStateInterface();
346 private final MockStorageMonitoringInterface mMockStorageMonitoringInterface =
347 new MockStorageMonitoringInterface();
Enrico Granata0f72b742017-11-02 18:26:41 -0700348 private final MockTimeInterface mMockTimeInterface =
349 new MockTimeInterface();
Enrico Granata57738692018-02-23 15:35:07 -0800350 private TestContext mContext;
Enrico Granatab19bc322017-10-12 12:25:06 -0700351
Enrico Granata517a1e02017-09-20 16:15:50 -0700352 private CarStorageMonitoringManager mCarStorageMonitoringManager;
353
354 @Override
Enrico Granata57738692018-02-23 15:35:07 -0800355 protected MockContext getCarServiceContext() throws NameNotFoundException {
356 if (mContext == null) {
357 mContext = new TestContext(super.getCarServiceContext());
358 }
359 return mContext;
360 }
361
362 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700363 protected synchronized SystemInterface.Builder getSystemInterfaceBuilder() {
364 SystemInterface.Builder builder = super.getSystemInterfaceBuilder();
365 return builder.withSystemStateInterface(mMockSystemStateInterface)
366 .withStorageMonitoringInterface(mMockStorageMonitoringInterface)
Enrico Granata0f72b742017-11-02 18:26:41 -0700367 .withTimeInterface(mMockTimeInterface);
Enrico Granatab19bc322017-10-12 12:25:06 -0700368 }
369
370 @Override
Enrico Granata517a1e02017-09-20 16:15:50 -0700371 protected synchronized void configureFakeSystemInterface() {
Enrico Granata286cd8e2017-09-25 14:46:49 -0700372 try {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800373 final TestData wearData = PER_TEST_DATA.getOrDefault(getName(), TestData.DEFAULT);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700374 final WearHistory wearHistory = wearData.wearHistory;
375
Enrico Granatab19bc322017-10-12 12:25:06 -0700376 mMockStorageMonitoringInterface.setWearInformation(wearData.wearInformation);
Enrico Granata1690a622018-01-22 17:34:46 -0800377 mMockStorageMonitoringInterface.setWriteInfo(wearData.currentLifetimeWriteInfo);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700378
379 if (wearHistory != null) {
380 File wearHistoryFile = new File(getFakeSystemInterface().getFilesDir(),
381 CarStorageMonitoringService.WEAR_INFO_FILENAME);
382 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(wearHistoryFile))) {
383 wearHistory.writeToJson(jsonWriter);
384 }
385 }
386
387 if (wearData.uptime > 0) {
388 File uptimeFile = new File(getFakeSystemInterface().getFilesDir(),
Enrico Granatab19bc322017-10-12 12:25:06 -0700389 CarStorageMonitoringService.UPTIME_TRACKER_FILENAME);
Enrico Granata286cd8e2017-09-25 14:46:49 -0700390 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(uptimeFile))) {
391 jsonWriter.beginObject();
392 jsonWriter.name("uptime").value(wearData.uptime);
393 jsonWriter.endObject();
394 }
395 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700396
Enrico Granata1690a622018-01-22 17:34:46 -0800397 if (wearData.previousLifetimeWriteInfo.length > 0) {
398 File previousLifetimeFile = new File(getFakeSystemInterface().getFilesDir(),
399 CarStorageMonitoringService.LIFETIME_WRITES_FILENAME);
400 try (JsonWriter jsonWriter = new JsonWriter(new FileWriter(previousLifetimeFile))) {
401 jsonWriter.beginObject();
402 jsonWriter.name("lifetimeWriteInfo").beginArray();
403 for (LifetimeWriteInfo writeInfo : wearData.previousLifetimeWriteInfo) {
404 writeInfo.writeToJson(jsonWriter);
405 }
406 jsonWriter.endArray().endObject();
407 }
408 }
409
Enrico Granataa97fce22017-10-27 14:57:34 -0700410 Arrays.stream(wearData.ioStats).forEach(
411 mMockStorageMonitoringInterface::addIoStatsRecord);
412
Enrico Granata286cd8e2017-09-25 14:46:49 -0700413 } catch (IOException e) {
414 Log.e(TAG, "failed to configure fake system interface", e);
415 fail("failed to configure fake system interface instance");
416 }
Enrico Granata43024de2017-11-16 17:09:37 -0800417 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700418
Enrico Granata43024de2017-11-16 17:09:37 -0800419 @Override
420 protected synchronized void configureResourceOverrides(MockResources resources) {
Pavel Maltseved2c8642017-12-18 12:56:26 -0800421 final ResourceOverrides overrides = PER_TEST_RESOURCES.getOrDefault(getName(), null);
Enrico Granata43024de2017-11-16 17:09:37 -0800422 if (overrides != null) {
423 overrides.overrideResources(resources);
424 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700425 }
426
427 @Override
Pavel Maltseved2c8642017-12-18 12:56:26 -0800428 public void setUp() throws Exception {
Enrico Granata517a1e02017-09-20 16:15:50 -0700429 super.setUp();
Enrico Granatab19bc322017-10-12 12:25:06 -0700430 mMockSystemStateInterface.executeBootCompletedActions();
Enrico Granatacf53fd72017-09-28 10:45:44 -0700431
Enrico Granata517a1e02017-09-20 16:15:50 -0700432 mCarStorageMonitoringManager =
433 (CarStorageMonitoringManager) getCar().getCarManager(Car.STORAGE_MONITORING_SERVICE);
434 }
435
Pavel Maltseved2c8642017-12-18 12:56:26 -0800436 @Test
Enrico Granata517a1e02017-09-20 16:15:50 -0700437 public void testReadPreEolInformation() throws Exception {
Enrico Granata1172f882017-09-21 14:51:30 -0700438 assertEquals(DEFAULT_WEAR_INFORMATION.preEolInfo,
Enrico Granata517a1e02017-09-20 16:15:50 -0700439 mCarStorageMonitoringManager.getPreEolIndicatorStatus());
440 }
Enrico Granata1172f882017-09-21 14:51:30 -0700441
Pavel Maltseved2c8642017-12-18 12:56:26 -0800442 @Test
Enrico Granata1172f882017-09-21 14:51:30 -0700443 public void testReadWearEstimate() throws Exception {
444 final WearEstimate wearEstimate = mCarStorageMonitoringManager.getWearEstimate();
445
446 assertNotNull(wearEstimate);
447 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateA, wearEstimate.typeA);
448 assertEquals(DEFAULT_WEAR_INFORMATION.lifetimeEstimateB, wearEstimate.typeB);
449 }
Enrico Granata286cd8e2017-09-25 14:46:49 -0700450
Pavel Maltseved2c8642017-12-18 12:56:26 -0800451 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700452 public void testReadWearHistory() throws Exception {
453 final List<WearEstimateChange> wearEstimateChanges =
454 mCarStorageMonitoringManager.getWearEstimateHistory();
455
456 assertNotNull(wearEstimateChanges);
457 assertFalse(wearEstimateChanges.isEmpty());
458
Enrico Granataa97fce22017-10-27 14:57:34 -0700459 final WearHistory expectedWearHistory = PER_TEST_DATA.get(getName()).wearHistory;
Enrico Granata286cd8e2017-09-25 14:46:49 -0700460
461 assertEquals(expectedWearHistory.size(), wearEstimateChanges.size());
462 for (int i = 0; i < wearEstimateChanges.size(); ++i) {
463 final WearEstimateRecord expected = expectedWearHistory.get(i);
464 final WearEstimateChange actual = wearEstimateChanges.get(i);
465
466 assertTrue(expected.isSameAs(actual));
467 }
468 }
469
470 private void checkLastWearEvent(boolean isAcceptable) throws Exception {
471 final List<WearEstimateChange> wearEstimateChanges =
472 mCarStorageMonitoringManager.getWearEstimateHistory();
473
474 assertNotNull(wearEstimateChanges);
475 assertFalse(wearEstimateChanges.isEmpty());
476
Enrico Granataa97fce22017-10-27 14:57:34 -0700477 final TestData wearData = PER_TEST_DATA.get(getName());
Enrico Granata286cd8e2017-09-25 14:46:49 -0700478
479 final WearInformation expectedCurrentWear = wearData.wearInformation;
480 final WearEstimate expectedPreviousWear = wearData.wearHistory.getLast().getNewWearEstimate();
481
482 final WearEstimateChange actualCurrentWear =
483 wearEstimateChanges.get(wearEstimateChanges.size() - 1);
484
485 assertEquals(isAcceptable, actualCurrentWear.isAcceptableDegradation);
486 assertEquals(expectedCurrentWear.toWearEstimate(), actualCurrentWear.newEstimate);
487 assertEquals(expectedPreviousWear, actualCurrentWear.oldEstimate);
488 }
489
Pavel Maltseved2c8642017-12-18 12:56:26 -0800490 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700491 public void testNotAcceptableWearEvent() throws Exception {
492 checkLastWearEvent(false);
493 }
494
Pavel Maltseved2c8642017-12-18 12:56:26 -0800495 @Test
Enrico Granata286cd8e2017-09-25 14:46:49 -0700496 public void testAcceptableWearEvent() throws Exception {
497 checkLastWearEvent(true);
498 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700499
Pavel Maltseved2c8642017-12-18 12:56:26 -0800500 @Test
Enrico Granataa97fce22017-10-27 14:57:34 -0700501 public void testBootIoStats() throws Exception {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800502 final List<IoStatsEntry> bootIoStats =
Enrico Granataa97fce22017-10-27 14:57:34 -0700503 mCarStorageMonitoringManager.getBootIoStats();
504
505 assertNotNull(bootIoStats);
506 assertFalse(bootIoStats.isEmpty());
507
Enrico Granata7e0150d2017-11-06 17:20:17 -0800508 final UidIoRecord[] bootIoRecords = PER_TEST_DATA.get(getName()).ioStats;
Enrico Granataa97fce22017-10-27 14:57:34 -0700509
510 bootIoStats.forEach(uidIoStats -> assertTrue(Arrays.stream(bootIoRecords).anyMatch(
511 ioRecord -> uidIoStats.representsSameMetrics(ioRecord))));
512 }
513
Pavel Maltseved2c8642017-12-18 12:56:26 -0800514 @Test
Enrico Granata0f72b742017-11-02 18:26:41 -0700515 public void testAggregateIoStats() throws Exception {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800516 UidIoRecord oldRecord1000 = mMockStorageMonitoringInterface.getIoStatsRecord(1000);
Enrico Granata0f72b742017-11-02 18:26:41 -0700517
Enrico Granata7e0150d2017-11-06 17:20:17 -0800518 UidIoRecord newRecord1000 = new UidIoRecord(1000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700519 oldRecord1000.foreground_rchar,
520 oldRecord1000.foreground_wchar + 50,
521 oldRecord1000.foreground_read_bytes,
522 oldRecord1000.foreground_write_bytes + 100,
523 oldRecord1000.foreground_fsync + 1,
524 oldRecord1000.background_rchar,
525 oldRecord1000.background_wchar,
526 oldRecord1000.background_read_bytes,
527 oldRecord1000.background_write_bytes,
528 oldRecord1000.background_fsync);
529
530 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord1000);
531
Enrico Granata7e0150d2017-11-06 17:20:17 -0800532 UidIoRecord record2000 = new UidIoRecord(2000,
Enrico Granata0f72b742017-11-02 18:26:41 -0700533 1024,
534 2048,
535 0,
536 1024,
537 1,
538 0,
539 0,
540 0,
541 0,
542 0);
543
544 mMockStorageMonitoringInterface.addIoStatsRecord(record2000);
545
546 mMockTimeInterface.tick();
547
Enrico Granatadbda56f2017-12-18 11:53:22 -0800548 List<IoStatsEntry> aggregateIoStats = mCarStorageMonitoringManager.getAggregateIoStats();
Enrico Granata0f72b742017-11-02 18:26:41 -0700549
550 assertNotNull(aggregateIoStats);
551 assertFalse(aggregateIoStats.isEmpty());
552
553 aggregateIoStats.forEach(serviceIoStat -> {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800554 UidIoRecord mockIoStat = mMockStorageMonitoringInterface.getIoStatsRecord(
Enrico Granata0f72b742017-11-02 18:26:41 -0700555 serviceIoStat.uid);
556
557 assertNotNull(mockIoStat);
558
559 assertTrue(serviceIoStat.representsSameMetrics(mockIoStat));
560 });
561 }
562
Pavel Maltseved2c8642017-12-18 12:56:26 -0800563 @Test
Enrico Granata7e0150d2017-11-06 17:20:17 -0800564 public void testIoStatsDeltas() throws Exception {
565 UidIoRecord oldRecord0 = mMockStorageMonitoringInterface.getIoStatsRecord(0);
566
567 UidIoRecord newRecord0 = new UidIoRecord(0,
568 oldRecord0.foreground_rchar,
569 oldRecord0.foreground_wchar + 100,
570 oldRecord0.foreground_read_bytes,
571 oldRecord0.foreground_write_bytes + 50,
572 oldRecord0.foreground_fsync,
573 oldRecord0.background_rchar,
574 oldRecord0.background_wchar,
575 oldRecord0.background_read_bytes + 100,
576 oldRecord0.background_write_bytes,
577 oldRecord0.background_fsync);
578
579 mMockStorageMonitoringInterface.addIoStatsRecord(newRecord0);
580 mMockTimeInterface.setUptime(500).tick();
581
Enrico Granatadbda56f2017-12-18 11:53:22 -0800582 List<IoStats> deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800583 assertNotNull(deltas);
584 assertEquals(1, deltas.size());
585
Enrico Granatadbda56f2017-12-18 11:53:22 -0800586 IoStats delta0 = deltas.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800587 assertNotNull(delta0);
588 assertEquals(500, delta0.getTimestamp());
589
Enrico Granatadbda56f2017-12-18 11:53:22 -0800590 List<IoStatsEntry> delta0Stats = delta0.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800591 assertNotNull(delta0Stats);
592 assertEquals(1, delta0Stats.size());
593
Enrico Granatadbda56f2017-12-18 11:53:22 -0800594 IoStatsEntry deltaRecord0 = delta0Stats.get(0);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800595
596 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
597
598 UidIoRecord newerRecord0 = new UidIoRecord(0,
599 newRecord0.foreground_rchar + 200,
600 newRecord0.foreground_wchar + 10,
601 newRecord0.foreground_read_bytes,
602 newRecord0.foreground_write_bytes,
603 newRecord0.foreground_fsync,
604 newRecord0.background_rchar,
605 newRecord0.background_wchar + 100,
606 newRecord0.background_read_bytes,
607 newRecord0.background_write_bytes + 30,
608 newRecord0.background_fsync + 2);
609
610 mMockStorageMonitoringInterface.addIoStatsRecord(newerRecord0);
611 mMockTimeInterface.setUptime(1000).tick();
612
613 deltas = mCarStorageMonitoringManager.getIoStatsDeltas();
614 assertNotNull(deltas);
615 assertEquals(2, deltas.size());
616
617 delta0 = deltas.get(0);
618 assertNotNull(delta0);
619 assertEquals(500, delta0.getTimestamp());
620
621 delta0Stats = delta0.getStats();
622 assertNotNull(delta0Stats);
623 assertEquals(1, delta0Stats.size());
624
625 deltaRecord0 = delta0Stats.get(0);
626
627 assertTrue(deltaRecord0.representsSameMetrics(newRecord0.delta(oldRecord0)));
628
Enrico Granatadbda56f2017-12-18 11:53:22 -0800629 IoStats delta1 = deltas.get(1);
Enrico Granata7e0150d2017-11-06 17:20:17 -0800630 assertNotNull(delta1);
631 assertEquals(1000, delta1.getTimestamp());
632
Enrico Granatadbda56f2017-12-18 11:53:22 -0800633 List<IoStatsEntry> delta1Stats = delta1.getStats();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800634 assertNotNull(delta1Stats);
635 assertEquals(1, delta1Stats.size());
636
637 deltaRecord0 = delta1Stats.get(0);
638
639 assertTrue(deltaRecord0.representsSameMetrics(newerRecord0.delta(newRecord0)));
640 }
641
Pavel Maltseved2c8642017-12-18 12:56:26 -0800642 @Test
Enrico Granata7dce3792017-11-09 14:13:28 -0800643 public void testEventDelivery() throws Exception {
644 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
645
646 UidIoRecord record = new UidIoRecord(0,
647 0,
648 100,
649 0,
650 75,
651 1,
652 0,
653 0,
654 0,
655 0,
656 0);
657
658 Listener listener1 = new Listener("listener1");
659 Listener listener2 = new Listener("listener2");
660
661 mCarStorageMonitoringManager.registerListener(listener1);
662 mCarStorageMonitoringManager.registerListener(listener2);
663
664 mMockStorageMonitoringInterface.addIoStatsRecord(record);
665 mMockTimeInterface.setUptime(500).tick();
666
667 assertTrue(listener1.waitForEvent(eventDeliveryDeadline));
668 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
669
Enrico Granatadbda56f2017-12-18 11:53:22 -0800670 IoStats event1 = listener1.reset();
671 IoStats event2 = listener2.reset();
Enrico Granata7dce3792017-11-09 14:13:28 -0800672
673 assertEquals(event1, event2);
674 event1.getStats().forEach(stats -> assertTrue(stats.representsSameMetrics(record)));
675
676 mCarStorageMonitoringManager.unregisterListener(listener1);
677
678 mMockTimeInterface.setUptime(600).tick();
679 assertFalse(listener1.waitForEvent(eventDeliveryDeadline));
680 assertTrue(listener2.waitForEvent(eventDeliveryDeadline));
681 }
682
Pavel Maltseved2c8642017-12-18 12:56:26 -0800683 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800684 public void testIntentOnExcessiveWrite() throws Exception {
685 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
686
687 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
688
689 UidIoRecord record = new UidIoRecord(0,
690 0,
691 5120,
692 0,
693 5000,
694 1,
695 0,
696 7168,
697 0,
698 7000,
699 0);
700
701 mMockStorageMonitoringInterface.addIoStatsRecord(record);
702 mMockTimeInterface.setUptime(500).tick();
703
704 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
705 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
706 assertNotNull(deliveredIntent);
707 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
708 }
709
Pavel Maltseved2c8642017-12-18 12:56:26 -0800710 @Test
Enrico Granata43024de2017-11-16 17:09:37 -0800711 public void testIntentOnExcessiveFsync() throws Exception {
712 assertNull(CarStorageMonitoringBroadcastReceiver.reset());
713
714 final Duration intentDeliveryDeadline = Duration.ofSeconds(5);
715
716 UidIoRecord record = new UidIoRecord(0,
717 0,
718 0,
719 0,
720 0,
721 2,
722 0,
723 0,
724 0,
725 0,
726 3);
727
728 mMockStorageMonitoringInterface.addIoStatsRecord(record);
729 mMockTimeInterface.setUptime(500).tick();
730
731 assertTrue(CarStorageMonitoringBroadcastReceiver.waitForIntent(intentDeliveryDeadline));
732 Intent deliveredIntent = CarStorageMonitoringBroadcastReceiver.reset();
733 assertNotNull(deliveredIntent);
734 assertEquals(CarStorageMonitoringManager.INTENT_EXCESSIVE_IO, deliveredIntent.getAction());
735 }
736
Pavel Maltseved2c8642017-12-18 12:56:26 -0800737 @Test
Enrico Granata88d92c82017-11-30 16:47:15 -0800738 public void testZeroWindowDisablesCollection() throws Exception {
739 final Duration eventDeliveryDeadline = Duration.ofSeconds(5);
740
741 UidIoRecord record = new UidIoRecord(0,
742 0,
743 100,
744 0,
745 75,
746 1,
747 0,
748 0,
749 0,
750 0,
751 0);
752
753 Listener listener = new Listener("listener");
754
755 mMockStorageMonitoringInterface.addIoStatsRecord(record);
756 mMockTimeInterface.setUptime(500).tick();
757
758 assertFalse(listener.waitForEvent(eventDeliveryDeadline));
759
760 assertEquals(0, mCarStorageMonitoringManager.getIoStatsDeltas().size());
761 }
762
Enrico Granata1690a622018-01-22 17:34:46 -0800763 @Test
764 public void testComputeShutdownCost() throws Exception {
765 assertEquals(280, mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
766 }
767
768 @Test
769 public void testNegativeShutdownCost() throws Exception {
770 assertEquals(CarStorageMonitoringManager.SHUTDOWN_COST_INFO_MISSING,
771 mCarStorageMonitoringManager.getShutdownDiskWriteAmount());
772 }
773
Pavel Maltseved2c8642017-12-18 12:56:26 -0800774 private String getName() {
775 return mTestName.getMethodName();
776 }
777
Enrico Granatadbda56f2017-12-18 11:53:22 -0800778 static final class Listener implements CarStorageMonitoringManager.IoStatsListener {
Enrico Granata7dce3792017-11-09 14:13:28 -0800779 private final String mName;
780 private final Object mSync = new Object();
781
Enrico Granatadbda56f2017-12-18 11:53:22 -0800782 private IoStats mLastEvent = null;
Enrico Granata7dce3792017-11-09 14:13:28 -0800783
784 Listener(String name) {
785 mName = name;
786 }
787
Enrico Granatadbda56f2017-12-18 11:53:22 -0800788 IoStats reset() {
Enrico Granata7dce3792017-11-09 14:13:28 -0800789 synchronized (mSync) {
Enrico Granatadbda56f2017-12-18 11:53:22 -0800790 IoStats lastEvent = mLastEvent;
Enrico Granata7dce3792017-11-09 14:13:28 -0800791 mLastEvent = null;
792 return lastEvent;
793 }
794 }
795
796 boolean waitForEvent(Duration duration) {
797 long start = SystemClock.elapsedRealtime();
798 long end = start + duration.toMillis();
799 synchronized (mSync) {
800 while (mLastEvent == null && SystemClock.elapsedRealtime() < end) {
801 try {
802 mSync.wait(10L);
803 } catch (InterruptedException e) {
804 // ignore
805 }
806 }
807 }
808
809 return (mLastEvent != null);
810 }
811
812 @Override
Enrico Granatadbda56f2017-12-18 11:53:22 -0800813 public void onSnapshot(IoStats event) {
Enrico Granata7dce3792017-11-09 14:13:28 -0800814 synchronized (mSync) {
815 Log.d(TAG, "listener " + mName + " received event " + event);
816 // We're going to hold a reference to this object
817 mLastEvent = event;
818 mSync.notify();
819 }
820 }
821
822 }
823
Enrico Granatab19bc322017-10-12 12:25:06 -0700824 static final class MockStorageMonitoringInterface implements StorageMonitoringInterface,
825 WearInformationProvider {
826 private WearInformation mWearInformation = null;
Enrico Granata7e0150d2017-11-06 17:20:17 -0800827 private SparseArray<UidIoRecord> mIoStats = new SparseArray<>();
Enrico Granataa97fce22017-10-27 14:57:34 -0700828 private UidIoStatsProvider mIoStatsProvider = () -> mIoStats;
Enrico Granata1690a622018-01-22 17:34:46 -0800829 private LifetimeWriteInfo[] mWriteInfo = new LifetimeWriteInfo[0];
Enrico Granatab19bc322017-10-12 12:25:06 -0700830
831 void setWearInformation(WearInformation wearInformation) {
832 mWearInformation = wearInformation;
833 }
834
Enrico Granata1690a622018-01-22 17:34:46 -0800835 void setWriteInfo(LifetimeWriteInfo[] writeInfo) {
836 mWriteInfo = writeInfo;
837 }
838
Enrico Granata7e0150d2017-11-06 17:20:17 -0800839 void addIoStatsRecord(UidIoRecord record) {
Enrico Granataa97fce22017-10-27 14:57:34 -0700840 mIoStats.append(record.uid, record);
841 }
842
Enrico Granata7e0150d2017-11-06 17:20:17 -0800843 UidIoRecord getIoStatsRecord(int uid) {
Enrico Granata0f72b742017-11-02 18:26:41 -0700844 return mIoStats.get(uid);
845 }
846
Enrico Granataa97fce22017-10-27 14:57:34 -0700847 void deleteIoStatsRecord(int uid) {
848 mIoStats.delete(uid);
849 }
850
Enrico Granatab19bc322017-10-12 12:25:06 -0700851 @Override
852 public WearInformation load() {
853 return mWearInformation;
854 }
855
856 @Override
Enrico Granata1690a622018-01-22 17:34:46 -0800857 public LifetimeWriteInfoProvider getLifetimeWriteInfoProvider() {
858 // cannot make this directly implement because Java does not allow
859 // overloading based on return type and there already is a method named
860 // load() in WearInformationProvider
861 return new LifetimeWriteInfoProvider() {
862 @Override
863 public LifetimeWriteInfo[] load() {
864 return mWriteInfo;
865 }
866 };
867 }
868
869 @Override
Enrico Granatab19bc322017-10-12 12:25:06 -0700870 public WearInformationProvider[] getFlashWearInformationProviders() {
871 return new WearInformationProvider[] {this};
872 }
Enrico Granataa97fce22017-10-27 14:57:34 -0700873
874 @Override
875 public UidIoStatsProvider getUidIoStatsProvider() {
876 return mIoStatsProvider;
877 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700878 }
879
880 static final class MockTimeInterface implements TimeInterface {
Enrico Granata0f72b742017-11-02 18:26:41 -0700881 private final List<Pair<Runnable, Long>> mActionsList = new ArrayList<>();
Enrico Granata7e0150d2017-11-06 17:20:17 -0800882 private long mUptime = 0;
Enrico Granatab19bc322017-10-12 12:25:06 -0700883
884 @Override
885 public long getUptime(boolean includeDeepSleepTime) {
Enrico Granata7e0150d2017-11-06 17:20:17 -0800886 return mUptime;
Enrico Granatab19bc322017-10-12 12:25:06 -0700887 }
888
889 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700890 public void scheduleAction(Runnable r, long delayMs) {
891 mActionsList.add(Pair.create(r, delayMs));
892 mActionsList.sort(Comparator.comparing(d -> d.second));
893 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700894
895 @Override
Enrico Granata0f72b742017-11-02 18:26:41 -0700896 public void cancelAllActions() {
897 mActionsList.clear();
898 }
899
900 void tick() {
901 mActionsList.forEach(pair -> pair.first.run());
902 }
Enrico Granata7e0150d2017-11-06 17:20:17 -0800903
904 MockTimeInterface setUptime(long time) {
905 mUptime = time;
906 return this;
907 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700908 }
909
910 static final class MockSystemStateInterface implements SystemStateInterface {
911 private final List<Pair<Runnable, Duration>> mActionsList = new ArrayList<>();
912
913 @Override
914 public void shutdown() {}
915
916 @Override
Steve Paik0f9fc002018-02-09 17:42:00 -0800917 public boolean enterDeepSleep(int wakeupTimeSec) {
918 return true;
919 }
Enrico Granatab19bc322017-10-12 12:25:06 -0700920
921 @Override
922 public void scheduleActionForBootCompleted(Runnable action, Duration delay) {
923 mActionsList.add(Pair.create(action, delay));
924 mActionsList.sort(Comparator.comparing(d -> d.second));
925 }
926
927 void executeBootCompletedActions() {
928 for (Pair<Runnable, Duration> action : mActionsList) {
929 action.first.run();
930 }
931 }
932 }
Enrico Granata517a1e02017-09-20 16:15:50 -0700933}