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