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.os.Parcel; 22 import android.os.Parcelable; 23 import android.util.JsonWriter; 24 25 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 26 27 import org.json.JSONException; 28 import org.json.JSONObject; 29 30 import java.io.IOException; 31 import java.util.Objects; 32 33 /** 34 * uid_io stats about one user ID. 35 * 36 * Contains information about I/O activity that can be attributed to processes running on 37 * behalf of one user of the system, as collected by the kernel. 38 * 39 * @hide 40 * 41 * @deprecated use {@link android.car.watchdog.CarWatchdogManager} and its related classes 42 * for I/O related tasks. 43 */ 44 @Deprecated 45 @SystemApi 46 public final class IoStatsEntry implements Parcelable { 47 48 public static final Parcelable.Creator<IoStatsEntry> CREATOR = 49 new Parcelable.Creator<IoStatsEntry>() { 50 51 public IoStatsEntry createFromParcel(Parcel in) { 52 return new IoStatsEntry(in); 53 } 54 55 public IoStatsEntry[] newArray(int size) { 56 return new IoStatsEntry[size]; 57 } 58 }; 59 60 /** 61 * The user id that this object contains metrics for. 62 * 63 * In many cases this can be converted to a list of Java app packages installed on the device. 64 * In other cases, the user id can refer to either the kernel itself (uid 0), or low-level 65 * system services that are running entirely natively. 66 */ 67 public final int uid; 68 69 /** 70 * How long any process running on behalf of this user id running for, in milliseconds. 71 * 72 * This field is allowed to be an approximation and it does not provide any way to 73 * relate uptime to specific processes. 74 */ 75 public final long runtimeMillis; 76 77 /** 78 * Statistics for apps running in foreground. 79 */ 80 public final IoStatsEntry.Metrics foreground; 81 82 /** 83 * Statistics for apps running in background. 84 */ 85 public final IoStatsEntry.Metrics background; 86 IoStatsEntry(int uid, long runtimeMillis, IoStatsEntry.Metrics foreground, IoStatsEntry.Metrics background)87 public IoStatsEntry(int uid, 88 long runtimeMillis, IoStatsEntry.Metrics foreground, IoStatsEntry.Metrics background) { 89 this.uid = uid; 90 this.runtimeMillis = runtimeMillis; 91 this.foreground = Objects.requireNonNull(foreground); 92 this.background = Objects.requireNonNull(background); 93 } 94 IoStatsEntry(Parcel in)95 public IoStatsEntry(Parcel in) { 96 uid = in.readInt(); 97 runtimeMillis = in.readLong(); 98 foreground = in.readParcelable(IoStatsEntry.Metrics.class.getClassLoader()); 99 background = in.readParcelable(IoStatsEntry.Metrics.class.getClassLoader()); 100 } 101 IoStatsEntry(UidIoRecord record, long runtimeMillis)102 public IoStatsEntry(UidIoRecord record, long runtimeMillis) { 103 uid = record.uid; 104 this.runtimeMillis = runtimeMillis; 105 foreground = new IoStatsEntry.Metrics(record.foreground_rchar, 106 record.foreground_wchar, 107 record.foreground_read_bytes, 108 record.foreground_write_bytes, 109 record.foreground_fsync); 110 background = new IoStatsEntry.Metrics(record.background_rchar, 111 record.background_wchar, 112 record.background_read_bytes, 113 record.background_write_bytes, 114 record.background_fsync); 115 } 116 117 @Override 118 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) describeContents()119 public int describeContents() { 120 return 0; 121 } 122 123 @Override writeToParcel(Parcel dest, int flags)124 public void writeToParcel(Parcel dest, int flags) { 125 dest.writeInt(uid); 126 dest.writeLong(runtimeMillis); 127 dest.writeParcelable(foreground, flags); 128 dest.writeParcelable(background, flags); 129 } 130 131 /** 132 * @hide 133 */ writeToJson(JsonWriter jsonWriter)134 public void writeToJson(JsonWriter jsonWriter) throws IOException { 135 jsonWriter.beginObject(); 136 jsonWriter.name("uid").value(uid); 137 jsonWriter.name("runtimeMillis").value(runtimeMillis); 138 jsonWriter.name("foreground"); foreground.writeToJson(jsonWriter); 139 jsonWriter.name("background"); background.writeToJson(jsonWriter); 140 jsonWriter.endObject(); 141 } 142 143 /** 144 * @hide 145 */ IoStatsEntry(JSONObject in)146 public IoStatsEntry(JSONObject in) throws JSONException { 147 uid = in.getInt("uid"); 148 runtimeMillis = in.getLong("runtimeMillis"); 149 foreground = new IoStatsEntry.Metrics(in.getJSONObject("foreground")); 150 background = new IoStatsEntry.Metrics(in.getJSONObject("background")); 151 } 152 153 /** 154 * Returns the difference between the values stored in this object vs. those 155 * stored in other. 156 * 157 * It is the same as doing a delta() on foreground and background, plus verifying that 158 * both objects refer to the same uid. 159 * 160 * @hide 161 */ delta(IoStatsEntry other)162 public IoStatsEntry delta(IoStatsEntry other) { 163 if (uid != other.uid) { 164 throw new IllegalArgumentException("cannot calculate delta between different user IDs"); 165 } 166 return new IoStatsEntry(uid, 167 runtimeMillis - other.runtimeMillis, 168 foreground.delta(other.foreground), background.delta(other.background)); 169 } 170 171 @Override equals(Object other)172 public boolean equals(Object other) { 173 if (other instanceof IoStatsEntry) { 174 IoStatsEntry uidIoStatEntry = (IoStatsEntry) other; 175 176 return uid == uidIoStatEntry.uid 177 && runtimeMillis == uidIoStatEntry.runtimeMillis 178 && foreground.equals(uidIoStatEntry.foreground) 179 && background.equals(uidIoStatEntry.background); 180 } 181 return false; 182 } 183 184 @Override hashCode()185 public int hashCode() { 186 return Objects.hash(uid, runtimeMillis, foreground, background); 187 } 188 189 @Override toString()190 public String toString() { 191 return String.format("uid = %d, runtime = %d, foreground = %s, background = %s", 192 uid, runtimeMillis, foreground, background); 193 } 194 195 /** 196 * Validates that this object contains the same I/O metrics as a UidIoStatsRecord. 197 * 198 * It matches UID, and I/O activity values, but ignores runtime. 199 * @hide 200 */ representsSameMetrics(UidIoRecord record)201 public boolean representsSameMetrics(UidIoRecord record) { 202 return record.uid == uid 203 && record.foreground_rchar == foreground.bytesRead 204 && record.foreground_wchar == foreground.bytesWritten 205 && record.foreground_read_bytes == foreground.bytesReadFromStorage 206 && record.foreground_write_bytes == foreground.bytesWrittenToStorage 207 && record.foreground_fsync == foreground.fsyncCalls 208 && record.background_rchar == background.bytesRead 209 && record.background_wchar == background.bytesWritten 210 && record.background_read_bytes == background.bytesReadFromStorage 211 && record.background_write_bytes == background.bytesWrittenToStorage 212 && record.background_fsync == background.fsyncCalls; 213 } 214 215 /** 216 * I/O activity metrics that pertain to either the foreground or the background state. 217 */ 218 public static final class Metrics implements Parcelable { 219 220 public static final Parcelable.Creator<IoStatsEntry.Metrics> CREATOR = 221 new Parcelable.Creator<IoStatsEntry.Metrics>() { 222 public IoStatsEntry.Metrics createFromParcel(Parcel in) { 223 return new IoStatsEntry.Metrics(in); 224 } 225 226 public IoStatsEntry.Metrics[] newArray(int size) { 227 return new IoStatsEntry.Metrics[size]; 228 } 229 }; 230 231 /** 232 * Total bytes that processes running on behalf of this user obtained 233 * via read() system calls. 234 */ 235 public final long bytesRead; 236 237 /** 238 * Total bytes that processes running on behalf of this user transferred 239 * via write() system calls. 240 */ 241 public final long bytesWritten; 242 243 /** 244 * Total bytes that processes running on behalf of this user obtained 245 * via read() system calls that actually were served by physical storage. 246 */ 247 public final long bytesReadFromStorage; 248 249 /** 250 * Total bytes that processes running on behalf of this user transferred 251 * via write() system calls that were actually sent to physical storage. 252 */ 253 public final long bytesWrittenToStorage; 254 255 /** 256 * Total number of fsync() system calls that processes running on behalf of this user made. 257 */ 258 public final long fsyncCalls; 259 Metrics(long bytesRead, long bytesWritten, long bytesReadFromStorage, long bytesWrittenToStorage, long fsyncCalls)260 public Metrics(long bytesRead, long bytesWritten, long bytesReadFromStorage, 261 long bytesWrittenToStorage, long fsyncCalls) { 262 this.bytesRead = bytesRead; 263 this.bytesWritten = bytesWritten; 264 this.bytesReadFromStorage = bytesReadFromStorage; 265 this.bytesWrittenToStorage = bytesWrittenToStorage; 266 this.fsyncCalls = fsyncCalls; 267 } 268 269 @Override describeContents()270 public int describeContents() { 271 return 0; 272 } 273 274 @Override writeToParcel(Parcel dest, int flags)275 public void writeToParcel(Parcel dest, int flags) { 276 dest.writeLong(bytesRead); 277 dest.writeLong(bytesWritten); 278 dest.writeLong(bytesReadFromStorage); 279 dest.writeLong(bytesWrittenToStorage); 280 dest.writeLong(fsyncCalls); 281 } 282 283 /** 284 * @hide 285 */ writeToJson(JsonWriter jsonWriter)286 public void writeToJson(JsonWriter jsonWriter) throws IOException { 287 jsonWriter.beginObject(); 288 jsonWriter.name("bytesRead").value(bytesRead); 289 jsonWriter.name("bytesWritten").value(bytesWritten); 290 jsonWriter.name("bytesReadFromStorage").value(bytesReadFromStorage); 291 jsonWriter.name("bytesWrittenToStorage").value(bytesWrittenToStorage); 292 jsonWriter.name("fsyncCalls").value(fsyncCalls); 293 jsonWriter.endObject(); 294 } 295 Metrics(Parcel in)296 public Metrics(Parcel in) { 297 bytesRead = in.readLong(); 298 bytesWritten = in.readLong(); 299 bytesReadFromStorage = in.readLong(); 300 bytesWrittenToStorage = in.readLong(); 301 fsyncCalls = in.readLong(); 302 } 303 304 /** 305 * @hide 306 */ Metrics(JSONObject in)307 public Metrics(JSONObject in) throws JSONException { 308 bytesRead = in.getLong("bytesRead"); 309 bytesWritten = in.getLong("bytesWritten"); 310 bytesReadFromStorage = in.getLong("bytesReadFromStorage"); 311 bytesWrittenToStorage = in.getLong("bytesWrittenToStorage"); 312 fsyncCalls = in.getLong("fsyncCalls"); 313 } 314 315 /** 316 * Computes the difference between the values stored in this object 317 * vs. those stored in other 318 * 319 * It is the same as doing 320 * new PerStateMetrics(bytesRead-other.bytesRead,bytesWritten-other.bytesWritten, ...) 321 * 322 * @hide 323 */ delta(Metrics other)324 public Metrics delta(Metrics other) { 325 return new Metrics(bytesRead - other.bytesRead, 326 bytesWritten - other.bytesWritten, 327 bytesReadFromStorage - other.bytesReadFromStorage, 328 bytesWrittenToStorage - other.bytesWrittenToStorage, 329 fsyncCalls - other.fsyncCalls); 330 } 331 332 @Override equals(Object other)333 public boolean equals(Object other) { 334 if (other instanceof Metrics) { 335 Metrics metrics = (Metrics) other; 336 337 return (bytesRead == metrics.bytesRead) 338 && (bytesWritten == metrics.bytesWritten) 339 && (bytesReadFromStorage == metrics.bytesReadFromStorage) 340 && (bytesWrittenToStorage == metrics.bytesWrittenToStorage) 341 && (fsyncCalls == metrics.fsyncCalls); 342 } 343 return false; 344 } 345 346 @Override hashCode()347 public int hashCode() { 348 return Objects.hash(bytesRead, bytesWritten, bytesReadFromStorage, 349 bytesWrittenToStorage, fsyncCalls); 350 } 351 352 @Override toString()353 public String toString() { 354 return String.format("bytesRead=%d, bytesWritten=%d, bytesReadFromStorage=%d, " 355 + "bytesWrittenToStorage=%d, fsyncCalls=%d", bytesRead, bytesWritten, 356 bytesReadFromStorage, bytesWrittenToStorage, fsyncCalls); 357 } 358 } 359 } 360