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