• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 package com.android.car.storagemonitoring;
17 
18 import android.annotation.NonNull;
19 import android.car.storagemonitoring.WearEstimateChange;
20 import android.util.JsonWriter;
21 
22 import org.json.JSONArray;
23 import org.json.JSONException;
24 import org.json.JSONObject;
25 
26 import java.io.File;
27 import java.io.IOException;
28 import java.nio.file.Files;
29 import java.time.Duration;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.List;
34 
35 /**
36  * This class represents the entire history of flash wear changes as tracked
37  * by CarStorageMonitoringService. It is a set of WearEstimateRecords.
38  *
39  * This is convertible to a list of WearEstimateChanges given policy about what constitutes
40  * acceptable or not acceptable degradation across change events. This policy is subject to
41  * modifications across OS versions, and as such it is not suitable for permanent storage.
42  */
43 public class WearHistory {
44     private final List<WearEstimateRecord> mWearHistory = new ArrayList<>();
45 
WearHistory()46     public WearHistory() {}
47 
WearHistory(@onNull JSONObject jsonObject)48     WearHistory(@NonNull JSONObject jsonObject) throws JSONException {
49         final JSONArray wearHistory = jsonObject.getJSONArray("wearHistory");
50         for (int i = 0; i < wearHistory.length(); ++i) {
51             JSONObject wearRecordJson = wearHistory.getJSONObject(i);
52             WearEstimateRecord wearRecord = new WearEstimateRecord(wearRecordJson);
53             add(wearRecord);
54         }
55     }
56 
fromRecords(@onNull WearEstimateRecord... records)57     public static WearHistory fromRecords(@NonNull WearEstimateRecord... records) {
58         WearHistory wearHistory = new WearHistory();
59         Arrays.stream(records).forEach(wearHistory::add);
60         return wearHistory;
61     }
62 
fromJson(@onNull File in)63     public static WearHistory fromJson(@NonNull File in) throws IOException, JSONException {
64         JSONObject jsonObject = new JSONObject(new String(Files.readAllBytes(in.toPath())));
65         return new WearHistory(jsonObject);
66     }
67 
writeToJson(@onNull JsonWriter out)68     public void writeToJson(@NonNull JsonWriter out) throws IOException {
69         out.beginObject();
70         out.name("wearHistory").beginArray();
71         for (WearEstimateRecord wearRecord : mWearHistory) {
72             wearRecord.writeToJson(out);
73         }
74         out.endArray();
75         out.endObject();
76     }
77 
add(@onNull WearEstimateRecord record)78     public boolean add(@NonNull WearEstimateRecord record) {
79         if (record != null && mWearHistory.add(record)) {
80             mWearHistory.sort((WearEstimateRecord o1, WearEstimateRecord o2) ->
81                 Long.valueOf(o1.getTotalCarServiceUptime()).compareTo(
82                     o2.getTotalCarServiceUptime()));
83             return true;
84         }
85         return false;
86     }
87 
size()88     public int size() {
89         return mWearHistory.size();
90     }
91 
get(int i)92     public WearEstimateRecord get(int i) {
93         return mWearHistory.get(i);
94     }
95 
getLast()96     public WearEstimateRecord getLast() {
97         return get(size() - 1);
98     }
99 
toWearEstimateChanges( long acceptableHoursPerOnePercentFlashWear)100     public List<WearEstimateChange> toWearEstimateChanges(
101             long acceptableHoursPerOnePercentFlashWear) {
102         // current technology allows us to detect wear in 10% increments
103         final int WEAR_PERCENTAGE_INCREMENT = 10;
104         final long acceptableWearRate = WEAR_PERCENTAGE_INCREMENT *
105                 Duration.ofHours(acceptableHoursPerOnePercentFlashWear).toMillis();
106         final int numRecords = size();
107 
108         if (numRecords == 0) return Collections.emptyList();
109 
110         List<WearEstimateChange> result = new ArrayList<>();
111         result.add(get(0).toWearEstimateChange(true));
112 
113         for (int i = 1; i < numRecords; ++i) {
114             WearEstimateRecord previousRecord = get(i - 1);
115             WearEstimateRecord currentRecord = get(i);
116             final long timeForChange =
117                     currentRecord.getTotalCarServiceUptime() -
118                             previousRecord.getTotalCarServiceUptime();
119             final boolean isAcceptableDegradation = timeForChange >= acceptableWearRate;
120             result.add(currentRecord.toWearEstimateChange(isAcceptableDegradation));
121         }
122 
123         return Collections.unmodifiableList(result);
124     }
125 
126     @Override
equals(Object other)127     public boolean equals(Object other) {
128         if (other instanceof WearHistory) {
129             WearHistory wi = (WearHistory)other;
130             return wi.mWearHistory.equals(mWearHistory);
131         }
132         return false;
133     }
134 
135     @Override
hashCode()136     public int hashCode() {
137         return mWearHistory.hashCode();
138     }
139 
140     @Override
toString()141     public String toString() {
142         return mWearHistory.stream().map(WearEstimateRecord::toString).reduce(
143             "WearHistory[size = " + size() + "] -> ",
144             (String s, String t) -> s + ", " + t);
145     }
146 }
147