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 android.car.storagemonitoring;
17 
18 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
19 
20 import android.annotation.IntRange;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.JsonReader;
25 import android.util.JsonWriter;
26 
27 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
28 
29 import org.json.JSONException;
30 import org.json.JSONObject;
31 
32 import java.io.IOException;
33 import java.util.Objects;
34 
35 /**
36  * Wear-out information for flash storage.
37  *
38  * Contains a lower-bound estimate of the wear of "type A" (SLC) and "type B" (MLC) storage.
39  *
40  * Current technology offers wear data in increments of 10% (i.e. from 0 == new device up to
41  * 100 == worn-out device). It is possible for a storage device to only support one type of memory
42  * cell, in which case it is expected that the storage type not supported will have UNKNOWN wear.
43  *
44  * @hide
45  */
46 @SystemApi
47 public final class WearEstimate implements Parcelable {
48     public static final int UNKNOWN = -1;
49 
50     /** @hide */
51     public static final WearEstimate UNKNOWN_ESTIMATE = new WearEstimate(UNKNOWN, UNKNOWN);
52 
53     public static final Parcelable.Creator<WearEstimate> CREATOR =
54             new Parcelable.Creator<WearEstimate>() {
55         public WearEstimate createFromParcel(Parcel in) {
56                 return new WearEstimate(in);
57             }
58             public WearEstimate[] newArray(int size) {
59                 return new WearEstimate[size];
60             }
61         };
62 
63     /**
64      * Wear estimate data for "type A" storage.
65      */
66     @IntRange(from = -1, to = 100)
67     public final int typeA;
68 
69     /**
70      * Wear estimate data for "type B" storage.
71      */
72     @IntRange(from = -1, to = 100)
73     public final int typeB;
74 
validateWearValue(int value)75     private static int validateWearValue(int value) {
76         if (value == UNKNOWN) return value;
77         if ((value >= 0) && (value <= 100)) return value;
78         throw new IllegalArgumentException(value + " is not a valid wear estimate");
79     }
80 
WearEstimate(int typeA, int typeB)81     public WearEstimate(int typeA, int typeB) {
82         this.typeA = validateWearValue(typeA);
83         this.typeB = validateWearValue(typeB);
84     }
85 
WearEstimate(Parcel in)86     public WearEstimate(Parcel in) {
87         typeA = validateWearValue(in.readInt());
88         typeB = validateWearValue(in.readInt());
89     }
90 
91     /**
92      * @hide
93      */
WearEstimate(JsonReader in)94     public WearEstimate(JsonReader in) throws IOException {
95         int typeA = UNKNOWN;
96         int typeB = UNKNOWN;
97         in.beginObject();
98         while (in.hasNext()) {
99             switch (in.nextName()) {
100                 case "wearEstimateTypeA":
101                     typeA = validateWearValue(in.nextInt());
102                     break;
103                 case "wearEstimateTypeB":
104                     typeB = validateWearValue(in.nextInt());
105                     break;
106                 default:
107                     break;
108             }
109         }
110         in.endObject();
111         this.typeA = typeA;
112         this.typeB = typeB;
113     }
114 
115     /** @hide */
WearEstimate(JSONObject in)116     public WearEstimate(JSONObject in) throws JSONException {
117         typeA = in.getInt("wearEstimateTypeA");
118         typeB = in.getInt("wearEstimateTypeB");
119     }
120 
121     @Override
122     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
describeContents()123     public int describeContents() {
124         return 0;
125     }
126 
127     @Override
writeToParcel(Parcel dest, int flags)128     public void writeToParcel(Parcel dest, int flags) {
129         dest.writeInt(typeA);
130         dest.writeInt(typeB);
131     }
132 
133     /**
134      * @hide
135      */
writeToJson(JsonWriter jsonWriter)136     public void writeToJson(JsonWriter jsonWriter) throws IOException {
137         jsonWriter.beginObject();
138         jsonWriter.name("wearEstimateTypeA").value(typeA);
139         jsonWriter.name("wearEstimateTypeB").value(typeB);
140         jsonWriter.endObject();
141     }
142 
143     @Override
equals(Object other)144     public boolean equals(Object other) {
145         if (other instanceof WearEstimate) {
146             WearEstimate wo = (WearEstimate) other;
147             return wo.typeA == typeA && wo.typeB == typeB;
148         }
149         return false;
150     }
151 
152     @Override
hashCode()153     public int hashCode() {
154         return Objects.hash(typeA, typeB);
155     }
156 
wearValueToString(int value)157     private static String wearValueToString(int value) {
158         if (value == UNKNOWN) return "unknown";
159         return value + "%";
160     }
161 
162     @Override
toString()163     public String toString() {
164         return "type A: " + wearValueToString(typeA) + ", type B: " + wearValueToString(typeB);
165     }
166 }
167