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