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