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