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 17 package com.android.car.storagemonitoring; 18 19 import android.annotation.NonNull; 20 import android.car.storagemonitoring.WearEstimate; 21 import android.car.storagemonitoring.WearEstimateChange; 22 import android.util.JsonWriter; 23 import java.io.IOException; 24 import java.time.Instant; 25 import java.util.Objects; 26 import org.json.JSONException; 27 import org.json.JSONObject; 28 29 /** 30 * This class represents a wear estimate record as stored by CarStorageMonitoringService. 31 * 32 * Because it is meant to map 1:1 to on-disk records, it is not directly convertible to a 33 * WearEstimateChange because it does not include information about "acceptable degradation". 34 */ 35 public class WearEstimateRecord { 36 37 private final WearEstimate mOldWearEstimate; 38 private final WearEstimate mNewWearEstimate; 39 private final long mTotalCarServiceUptime; 40 private final Instant mUnixTimestamp; 41 WearEstimateRecord(@onNull WearEstimate oldWearEstimate, @NonNull WearEstimate newWearEstimate, long totalCarServiceUptime, @NonNull Instant unixTimestamp)42 public WearEstimateRecord(@NonNull WearEstimate oldWearEstimate, 43 @NonNull WearEstimate newWearEstimate, 44 long totalCarServiceUptime, 45 @NonNull Instant unixTimestamp) { 46 mOldWearEstimate = Objects.requireNonNull(oldWearEstimate); 47 mNewWearEstimate = Objects.requireNonNull(newWearEstimate); 48 mTotalCarServiceUptime = totalCarServiceUptime; 49 mUnixTimestamp = Objects.requireNonNull(unixTimestamp); 50 } 51 WearEstimateRecord(@onNull JSONObject json)52 WearEstimateRecord(@NonNull JSONObject json) throws JSONException { 53 mOldWearEstimate = new WearEstimate(json.getJSONObject("oldWearEstimate")); 54 mNewWearEstimate = new WearEstimate(json.getJSONObject("newWearEstimate")); 55 mTotalCarServiceUptime = json.getLong("totalCarServiceUptime"); 56 mUnixTimestamp = Instant.ofEpochMilli(json.getLong("unixTimestamp")); 57 58 } 59 writeToJson(@onNull JsonWriter jsonWriter)60 void writeToJson(@NonNull JsonWriter jsonWriter) throws IOException { 61 jsonWriter.beginObject(); 62 jsonWriter.name("oldWearEstimate"); mOldWearEstimate.writeToJson(jsonWriter); 63 jsonWriter.name("newWearEstimate"); mNewWearEstimate.writeToJson(jsonWriter); 64 jsonWriter.name("totalCarServiceUptime").value(mTotalCarServiceUptime); 65 jsonWriter.name("unixTimestamp").value(mUnixTimestamp.toEpochMilli()); 66 jsonWriter.endObject(); 67 } 68 getOldWearEstimate()69 public WearEstimate getOldWearEstimate() { 70 return mOldWearEstimate; 71 } 72 getNewWearEstimate()73 public WearEstimate getNewWearEstimate() { 74 return mNewWearEstimate; 75 } 76 getTotalCarServiceUptime()77 public long getTotalCarServiceUptime() { 78 return mTotalCarServiceUptime; 79 } 80 getUnixTimestamp()81 public Instant getUnixTimestamp() { 82 return mUnixTimestamp; 83 } 84 toWearEstimateChange(boolean isAcceptableDegradation)85 WearEstimateChange toWearEstimateChange(boolean isAcceptableDegradation) { 86 return new WearEstimateChange(mOldWearEstimate, 87 mNewWearEstimate, mTotalCarServiceUptime, mUnixTimestamp, isAcceptableDegradation); 88 } 89 90 @Override equals(Object other)91 public boolean equals(Object other) { 92 if (other instanceof WearEstimateRecord) { 93 WearEstimateRecord wer = (WearEstimateRecord)other; 94 if (!wer.mOldWearEstimate.equals(mOldWearEstimate)) return false; 95 if (!wer.mNewWearEstimate.equals(mNewWearEstimate)) return false; 96 if (wer.mTotalCarServiceUptime != mTotalCarServiceUptime) return false; 97 if (!wer.mUnixTimestamp.equals(mUnixTimestamp)) return false; 98 return true; 99 } 100 return false; 101 } 102 103 /** 104 * Checks whether this record tracks the same change as the provided estimate. 105 * That means the two objects have the same values for: 106 * <ul> 107 * <li>old wear indicators</li> 108 * <li>new wear indicators</li> 109 * <li>uptime at event</li> 110 * </ul> 111 */ isSameAs(@onNull WearEstimateChange wearEstimateChange)112 public boolean isSameAs(@NonNull WearEstimateChange wearEstimateChange) { 113 if (!mOldWearEstimate.equals(wearEstimateChange.oldEstimate)) return false; 114 if (!mNewWearEstimate.equals(wearEstimateChange.newEstimate)) return false; 115 return (mTotalCarServiceUptime == wearEstimateChange.uptimeAtChange); 116 } 117 118 @Override hashCode()119 public int hashCode() { 120 return Objects.hash(mOldWearEstimate, 121 mNewWearEstimate, mTotalCarServiceUptime, mUnixTimestamp); 122 } 123 124 @Override toString()125 public String toString() { 126 return String.format("WearEstimateRecord {" + 127 "mOldWearEstimate = %s, " + 128 "mNewWearEstimate = %s, " + 129 "mTotalCarServiceUptime = %d, " + 130 "mUnixTimestamp = %s}", 131 mOldWearEstimate, mNewWearEstimate, mTotalCarServiceUptime, mUnixTimestamp); 132 } 133 134 public static final class Builder { 135 private WearEstimate mOldWearEstimate = null; 136 private WearEstimate mNewWearEstimate = null; 137 private long mTotalCarServiceUptime = -1; 138 private Instant mUnixTimestamp = null; 139 Builder()140 private Builder() {} 141 newBuilder()142 public static Builder newBuilder() { 143 return new Builder(); 144 } 145 fromWearEstimate(@onNull WearEstimate wearEstimate)146 public Builder fromWearEstimate(@NonNull WearEstimate wearEstimate) { 147 mOldWearEstimate = Objects.requireNonNull(wearEstimate); 148 return this; 149 } 150 toWearEstimate(@onNull WearEstimate wearEstimate)151 public Builder toWearEstimate(@NonNull WearEstimate wearEstimate) { 152 mNewWearEstimate = Objects.requireNonNull(wearEstimate); 153 return this; 154 } 155 atUptime(long uptime)156 public Builder atUptime(long uptime) { 157 if (uptime < 0) { 158 throw new IllegalArgumentException("uptime must be >= 0"); 159 } 160 mTotalCarServiceUptime = uptime; 161 return this; 162 } 163 atTimestamp(@onNull Instant now)164 public Builder atTimestamp(@NonNull Instant now) { 165 mUnixTimestamp = Objects.requireNonNull(now); 166 return this; 167 } 168 build()169 public WearEstimateRecord build() { 170 if (mOldWearEstimate == null || mNewWearEstimate == null || 171 mTotalCarServiceUptime < 0 || mUnixTimestamp == null) { 172 throw new IllegalStateException("malformed builder state"); 173 } 174 return new WearEstimateRecord( 175 mOldWearEstimate, mNewWearEstimate, mTotalCarServiceUptime, mUnixTimestamp); 176 } 177 } 178 } 179