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.SystemApi;
21 import android.car.storagemonitoring.IoStatsEntry.Metrics;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.JsonWriter;
25 
26 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
27 
28 import org.json.JSONArray;
29 import org.json.JSONException;
30 import org.json.JSONObject;
31 
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Objects;
36 import java.util.StringJoiner;
37 
38 /**
39  * Delta of uid_io stats taken at a sample point.
40  *
41  * @hide
42  *
43  * @deprecated use {@link android.car.watchdog.CarWatchdogManager} and its related classes
44  * for I/O related tasks.
45  */
46 @Deprecated
47 @SystemApi
48 public final class IoStats implements Parcelable {
49     public static final Creator<IoStats> CREATOR = new Creator<IoStats>() {
50         @Override
51         public IoStats createFromParcel(Parcel in) {
52             return new IoStats(in);
53         }
54 
55         @Override
56         public IoStats[] newArray(int size) {
57             return new IoStats[size];
58         }
59     };
60 
61     private final List<IoStatsEntry> mStats;
62     private final long mUptimeTimestamp;
63 
IoStats(List<IoStatsEntry> stats, long timestamp)64     public IoStats(List<IoStatsEntry> stats, long timestamp) {
65         mStats = stats;
66         mUptimeTimestamp = timestamp;
67     }
68 
IoStats(Parcel in)69     public IoStats(Parcel in) {
70         mStats = in.createTypedArrayList(IoStatsEntry.CREATOR);
71         mUptimeTimestamp = in.readLong();
72     }
73 
74     /**
75      * @hide
76      */
IoStats(JSONObject in)77     public IoStats(JSONObject in) throws JSONException {
78         mUptimeTimestamp = in.getInt("uptime");
79         JSONArray statsArray = in.getJSONArray("stats");
80         mStats = new ArrayList<>();
81         for (int i = 0; i < statsArray.length(); ++i) {
82             mStats.add(new IoStatsEntry(statsArray.getJSONObject(i)));
83         }
84     }
85 
86     @Override
writeToParcel(Parcel dest, int flags)87     public void writeToParcel(Parcel dest, int flags) {
88         dest.writeTypedList(mStats);
89         dest.writeLong(mUptimeTimestamp);
90     }
91 
92     /**
93      * @hide
94      */
writeToJson(JsonWriter jsonWriter)95     public void writeToJson(JsonWriter jsonWriter) throws IOException {
96         jsonWriter.beginObject();
97         jsonWriter.name("uptime").value(mUptimeTimestamp);
98         jsonWriter.name("stats").beginArray();
99         for (IoStatsEntry stat : mStats) {
100             stat.writeToJson(jsonWriter);
101         }
102         jsonWriter.endArray();
103         jsonWriter.endObject();
104     }
105 
106     @Override
107     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
describeContents()108     public int describeContents() {
109         return 0;
110     }
111 
getTimestamp()112     public long getTimestamp() {
113         return mUptimeTimestamp;
114     }
115 
getStats()116     public List<IoStatsEntry> getStats() {
117         return mStats;
118     }
119 
120     @Override
hashCode()121     public int hashCode() {
122         return Objects.hash(mStats, mUptimeTimestamp);
123     }
124 
125     /**
126      * Returns user's stats ({@link IoStatsEntry}).
127      *
128      * @param uid Android's user id
129      */
getUserIdStats(int uid)130     public IoStatsEntry getUserIdStats(int uid) {
131         for (IoStatsEntry stats : getStats()) {
132             if (stats.uid == uid) {
133                 return stats;
134             }
135         }
136 
137         return null;
138     }
139 
140     /**
141      * Returns the following foreground total metrics: bytes written and read, bytes read from and
142      * written to storage, and number of sync calls.
143      */
getForegroundTotals()144     public IoStatsEntry.Metrics getForegroundTotals() {
145         long bytesRead = 0;
146         long bytesWritten = 0;
147         long bytesReadFromStorage = 0;
148         long bytesWrittenToStorage = 0;
149         long fsyncCalls = 0;
150 
151         for (IoStatsEntry stats : getStats()) {
152             bytesRead += stats.foreground.bytesRead;
153             bytesWritten += stats.foreground.bytesWritten;
154             bytesReadFromStorage += stats.foreground.bytesReadFromStorage;
155             bytesWrittenToStorage += stats.foreground.bytesWrittenToStorage;
156             fsyncCalls += stats.foreground.fsyncCalls;
157         }
158 
159         return new Metrics(bytesRead,
160                 bytesWritten,
161                 bytesReadFromStorage,
162                 bytesWrittenToStorage,
163                 fsyncCalls);
164     }
165 
166     /**
167      * Returns the following background total metrics: bytes written and read, bytes read from and
168      * written to storage, and number of sync calls.
169      */
getBackgroundTotals()170     public IoStatsEntry.Metrics getBackgroundTotals() {
171         long bytesRead = 0;
172         long bytesWritten = 0;
173         long bytesReadFromStorage = 0;
174         long bytesWrittenToStorage = 0;
175         long fsyncCalls = 0;
176 
177         for (IoStatsEntry stats : getStats()) {
178             bytesRead += stats.background.bytesRead;
179             bytesWritten += stats.background.bytesWritten;
180             bytesReadFromStorage += stats.background.bytesReadFromStorage;
181             bytesWrittenToStorage += stats.background.bytesWrittenToStorage;
182             fsyncCalls += stats.background.fsyncCalls;
183         }
184 
185         return new Metrics(bytesRead,
186             bytesWritten,
187             bytesReadFromStorage,
188             bytesWrittenToStorage,
189             fsyncCalls);
190     }
191 
192     /**
193      * Returns the sum of all foreground and background metrics (bytes written, bytes read from
194      * storage, bytes written to storage and number of sync calls).
195      */
getTotals()196     public IoStatsEntry.Metrics getTotals() {
197         IoStatsEntry.Metrics foreground = getForegroundTotals();
198         IoStatsEntry.Metrics background = getBackgroundTotals();
199 
200         return new IoStatsEntry.Metrics(foreground.bytesRead + background.bytesRead,
201                 foreground.bytesWritten + background.bytesWritten,
202                 foreground.bytesReadFromStorage + background.bytesReadFromStorage,
203                 foreground.bytesWrittenToStorage + background.bytesWrittenToStorage,
204                 foreground.fsyncCalls + background.fsyncCalls);
205     }
206 
207     @Override
equals(Object other)208     public boolean equals(Object other) {
209         if (other instanceof IoStats) {
210             IoStats delta = (IoStats) other;
211             return delta.getTimestamp() == getTimestamp()
212                 && delta.getStats().equals(getStats());
213         }
214         return false;
215     }
216 
217     @Override
toString()218     public String toString() {
219         StringJoiner stringJoiner = new StringJoiner(", ");
220         for (IoStatsEntry stats : getStats()) {
221             stringJoiner.add(stats.toString());
222         }
223         return "timestamp = " + getTimestamp() + ", stats = " + stringJoiner.toString();
224     }
225 }
226