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