1 /*
2  * Copyright (C) 2021 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 
17 package android.os;
18 
19 import android.annotation.NonNull;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 /**
25  * Snapshot of wake lock stats.
26  *
27  * @hide
28  */
29 @android.ravenwood.annotation.RavenwoodKeepWholeClass
30 public final class WakeLockStats implements Parcelable {
31 
32     public static class WakeLockData {
33 
34         public static final WakeLockData EMPTY = new WakeLockData(
35                 /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 0, /* timeHeldMs= */ 0);
36 
37         /** How many times this wakelock has been acquired. */
38         public final int timesAcquired;
39 
40         /** Time in milliseconds that the lock has been held in total. */
41         public final long totalTimeHeldMs;
42 
43         /**
44          * Time in milliseconds that the lock has been held or 0 if not currently holding the lock
45          */
46         public final long timeHeldMs;
47 
WakeLockData(int timesAcquired, long totalTimeHeldMs, long timeHeldMs)48         public WakeLockData(int timesAcquired, long totalTimeHeldMs, long timeHeldMs) {
49             this.timesAcquired = timesAcquired;
50             this.totalTimeHeldMs = totalTimeHeldMs;
51             this.timeHeldMs = timeHeldMs;
52         }
53 
54         /**
55          * Whether the fields are able to construct a valid wakelock.
56          */
isDataValid()57         public boolean isDataValid() {
58             final boolean isDataReasonable = timesAcquired > 0
59                     && totalTimeHeldMs > 0
60                     && timeHeldMs >= 0
61                     && totalTimeHeldMs >= timeHeldMs;
62             return isEmpty() || isDataReasonable;
63         }
64 
isEmpty()65         private boolean isEmpty() {
66             return timesAcquired == 0 && totalTimeHeldMs == 0 && timeHeldMs == 0;
67         }
68 
WakeLockData(Parcel in)69         private WakeLockData(Parcel in) {
70             timesAcquired = in.readInt();
71             totalTimeHeldMs = in.readLong();
72             timeHeldMs = in.readLong();
73         }
74 
writeToParcel(Parcel out)75         private void writeToParcel(Parcel out) {
76             out.writeInt(timesAcquired);
77             out.writeLong(totalTimeHeldMs);
78             out.writeLong(timeHeldMs);
79         }
80 
81         @Override
toString()82         public String toString() {
83             return "WakeLockData{"
84                 + "timesAcquired="
85                 + timesAcquired
86                 + ", totalTimeHeldMs="
87                 + totalTimeHeldMs
88                 + ", timeHeldMs="
89                 + timeHeldMs
90                 + "}";
91         }
92     }
93 
94     /** @hide */
95     public static class WakeLock {
96 
97         public static final String NAME_AGGREGATED = "wakelockstats_aggregated";
98 
99         public final int uid;
100         @NonNull public final String name;
101         public final boolean isAggregated;
102 
103         /** Wakelock data on both foreground and background. */
104         @NonNull public final WakeLockData totalWakeLockData;
105 
106         /** Wakelock data on background. */
107         @NonNull public final WakeLockData backgroundWakeLockData;
108 
WakeLock( int uid, @NonNull String name, boolean isAggregated, @NonNull WakeLockData totalWakeLockData, @NonNull WakeLockData backgroundWakeLockData)109         public WakeLock(
110                 int uid,
111                 @NonNull String name,
112                 boolean isAggregated,
113                 @NonNull WakeLockData totalWakeLockData,
114                 @NonNull WakeLockData backgroundWakeLockData) {
115             this.uid = uid;
116             this.name = name;
117             this.isAggregated = isAggregated;
118             this.totalWakeLockData = totalWakeLockData;
119             this.backgroundWakeLockData = backgroundWakeLockData;
120         }
121 
122         /** Whether the combination of total and background wakelock data is invalid. */
isDataValid( WakeLockData totalWakeLockData, WakeLockData backgroundWakeLockData)123         public static boolean isDataValid(
124                 WakeLockData totalWakeLockData, WakeLockData backgroundWakeLockData) {
125             return totalWakeLockData.totalTimeHeldMs > 0
126                 && totalWakeLockData.isDataValid()
127                 && backgroundWakeLockData.isDataValid()
128                 && totalWakeLockData.timesAcquired >= backgroundWakeLockData.timesAcquired
129                 && totalWakeLockData.totalTimeHeldMs >= backgroundWakeLockData.totalTimeHeldMs
130                 && totalWakeLockData.timeHeldMs >= backgroundWakeLockData.timeHeldMs;
131         }
132 
WakeLock(Parcel in)133         private WakeLock(Parcel in) {
134             uid = in.readInt();
135             name = in.readString();
136             isAggregated = in.readBoolean();
137             totalWakeLockData = new WakeLockData(in);
138             backgroundWakeLockData = new WakeLockData(in);
139         }
140 
writeToParcel(Parcel out)141         private void writeToParcel(Parcel out) {
142             out.writeInt(uid);
143             out.writeString(name);
144             out.writeBoolean(isAggregated);
145             totalWakeLockData.writeToParcel(out);
146             backgroundWakeLockData.writeToParcel(out);
147         }
148 
149         @Override
toString()150         public String toString() {
151             return "WakeLock{"
152                 + "uid="
153                 + uid
154                 + ", name='"
155                 + name
156                 + '\''
157                 + ", isAggregated="
158                 + isAggregated
159                 + ", totalWakeLockData="
160                 + totalWakeLockData
161                 + ", backgroundWakeLockData="
162                 + backgroundWakeLockData
163                 + '}';
164         }
165     }
166 
167     private final List<WakeLock> mWakeLocks;
168     private final List<WakeLock> mAggregatedWakeLocks;
169 
170     /** @hide */
WakeLockStats( @onNull List<WakeLock> wakeLocks, @NonNull List<WakeLock> aggregatedWakeLocks)171     public WakeLockStats(
172             @NonNull List<WakeLock> wakeLocks, @NonNull List<WakeLock> aggregatedWakeLocks) {
173         mWakeLocks = wakeLocks;
174         mAggregatedWakeLocks = aggregatedWakeLocks;
175     }
176 
177     @NonNull
getWakeLocks()178     public List<WakeLock> getWakeLocks() {
179         return mWakeLocks;
180     }
181 
182     @NonNull
getAggregatedWakeLocks()183     public List<WakeLock> getAggregatedWakeLocks() {
184         return mAggregatedWakeLocks;
185     }
186 
WakeLockStats(Parcel in)187     private WakeLockStats(Parcel in) {
188         final int wakelockSize = in.readInt();
189         mWakeLocks = new ArrayList<>(wakelockSize);
190         for (int i = 0; i < wakelockSize; i++) {
191             mWakeLocks.add(new WakeLock(in));
192         }
193         final int aggregatedWakelockSize = in.readInt();
194         mAggregatedWakeLocks = new ArrayList<>(aggregatedWakelockSize);
195         for (int i = 0; i < aggregatedWakelockSize; i++) {
196             mAggregatedWakeLocks.add(new WakeLock(in));
197         }
198     }
199 
200     @Override
writeToParcel(@onNull Parcel out, int flags)201     public void writeToParcel(@NonNull Parcel out, int flags) {
202         final int wakelockSize = mWakeLocks.size();
203         out.writeInt(wakelockSize);
204         for (int i = 0; i < wakelockSize; i++) {
205             WakeLock stats = mWakeLocks.get(i);
206             stats.writeToParcel(out);
207         }
208         final int aggregatedWakelockSize = mAggregatedWakeLocks.size();
209         out.writeInt(aggregatedWakelockSize);
210         for (int i = 0; i < aggregatedWakelockSize; i++) {
211             WakeLock stats = mAggregatedWakeLocks.get(i);
212             stats.writeToParcel(out);
213         }
214     }
215 
216     @NonNull
217     public static final Creator<WakeLockStats> CREATOR =
218             new Creator<WakeLockStats>() {
219                 public WakeLockStats createFromParcel(Parcel in) {
220                     return new WakeLockStats(in);
221                 }
222 
223                 public WakeLockStats[] newArray(int size) {
224                     return new WakeLockStats[size];
225                 }
226             };
227 
228     @Override
describeContents()229     public int describeContents() {
230         return 0;
231     }
232 
233     @Override
toString()234     public String toString() {
235         return "WakeLockStats{"
236             + "mWakeLocks: ["
237             + mWakeLocks
238             + "]"
239             + ", mAggregatedWakeLocks: ["
240             + mAggregatedWakeLocks
241             + "]"
242             + '}';
243     }
244 }
245