• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.text.TextUtils;
23 import android.util.TypedXmlPullParser;
24 import android.util.TypedXmlSerializer;
25 
26 import com.android.internal.os.PowerCalculator;
27 
28 import org.xmlpull.v1.XmlPullParser;
29 import org.xmlpull.v1.XmlPullParserException;
30 
31 import java.io.IOException;
32 import java.io.PrintWriter;
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 
36 /**
37  * Contains power consumption data attributed to a specific UID.
38  *
39  * @hide
40  */
41 public final class UidBatteryConsumer extends BatteryConsumer implements Parcelable {
42 
43     @Retention(RetentionPolicy.SOURCE)
44     @IntDef({
45             STATE_FOREGROUND,
46             STATE_BACKGROUND
47     })
48     public @interface State {
49     }
50 
51     /**
52      * The state of an application when it is either running a foreground (top) activity
53      * or a foreground service.
54      */
55     public static final int STATE_FOREGROUND = 0;
56 
57     /**
58      * The state of an application when it is running in the background, including the following
59      * states:
60      *
61      * {@link android.app.ActivityManager#PROCESS_STATE_IMPORTANT_BACKGROUND},
62      * {@link android.app.ActivityManager#PROCESS_STATE_TRANSIENT_BACKGROUND},
63      * {@link android.app.ActivityManager#PROCESS_STATE_BACKUP},
64      * {@link android.app.ActivityManager#PROCESS_STATE_SERVICE},
65      * {@link android.app.ActivityManager#PROCESS_STATE_RECEIVER}.
66      */
67     public static final int STATE_BACKGROUND = 1;
68 
69     private final int mUid;
70     @Nullable
71     private final String mPackageWithHighestDrain;
72     private final long mTimeInForegroundMs;
73     private final long mTimeInBackgroundMs;
74 
getUid()75     public int getUid() {
76         return mUid;
77     }
78 
79     @Nullable
getPackageWithHighestDrain()80     public String getPackageWithHighestDrain() {
81         return mPackageWithHighestDrain;
82     }
83 
84     /**
85      * Returns the amount of time in milliseconds this UID spent in the specified state.
86      */
getTimeInStateMs(@tate int state)87     public long getTimeInStateMs(@State int state) {
88         switch (state) {
89             case STATE_BACKGROUND:
90                 return mTimeInBackgroundMs;
91             case STATE_FOREGROUND:
92                 return mTimeInForegroundMs;
93         }
94         return 0;
95     }
96 
UidBatteryConsumer(@onNull Builder builder)97     private UidBatteryConsumer(@NonNull Builder builder) {
98         super(builder.mPowerComponentsBuilder.build());
99         mUid = builder.mUid;
100         mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
101         mTimeInForegroundMs = builder.mTimeInForegroundMs;
102         mTimeInBackgroundMs = builder.mTimeInBackgroundMs;
103     }
104 
UidBatteryConsumer(@onNull Parcel source)105     private UidBatteryConsumer(@NonNull Parcel source) {
106         super(new PowerComponents(source));
107         mUid = source.readInt();
108         mPackageWithHighestDrain = source.readString();
109         mTimeInForegroundMs = source.readLong();
110         mTimeInBackgroundMs = source.readLong();
111     }
112 
113     /**
114      * Writes the contents into a Parcel.
115      */
116     @Override
writeToParcel(@onNull Parcel dest, int flags)117     public void writeToParcel(@NonNull Parcel dest, int flags) {
118         super.writeToParcel(dest, flags);
119         dest.writeInt(mUid);
120         dest.writeString(mPackageWithHighestDrain);
121         dest.writeLong(mTimeInForegroundMs);
122         dest.writeLong(mTimeInBackgroundMs);
123     }
124 
125     @Override
dump(PrintWriter pw, boolean skipEmptyComponents)126     public void dump(PrintWriter pw, boolean skipEmptyComponents) {
127         final double consumedPower = getConsumedPower();
128         pw.print("UID ");
129         UserHandle.formatUid(pw, getUid());
130         pw.print(": ");
131         PowerCalculator.printPowerMah(pw, consumedPower);
132         pw.print(" ( ");
133         mPowerComponents.dump(pw, skipEmptyComponents  /* skipTotalPowerComponent */);
134         pw.print(" ) ");
135     }
136 
137     @NonNull
138     public static final Creator<UidBatteryConsumer> CREATOR = new Creator<UidBatteryConsumer>() {
139         public UidBatteryConsumer createFromParcel(@NonNull Parcel source) {
140             return new UidBatteryConsumer(source);
141         }
142 
143         public UidBatteryConsumer[] newArray(int size) {
144             return new UidBatteryConsumer[size];
145         }
146     };
147 
148     @Override
describeContents()149     public int describeContents() {
150         return 0;
151     }
152 
153     /** Serializes this object to XML */
writeToXml(TypedXmlSerializer serializer)154     void writeToXml(TypedXmlSerializer serializer) throws IOException {
155         if (getConsumedPower() == 0) {
156             return;
157         }
158 
159         serializer.startTag(null, BatteryUsageStats.XML_TAG_UID);
160         serializer.attributeInt(null, BatteryUsageStats.XML_ATTR_UID, getUid());
161         if (!TextUtils.isEmpty(mPackageWithHighestDrain)) {
162             serializer.attribute(null, BatteryUsageStats.XML_ATTR_HIGHEST_DRAIN_PACKAGE,
163                     mPackageWithHighestDrain);
164         }
165         serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND,
166                 mTimeInForegroundMs);
167         serializer.attributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_BACKGROUND,
168                 mTimeInBackgroundMs);
169         mPowerComponents.writeToXml(serializer);
170         serializer.endTag(null, BatteryUsageStats.XML_TAG_UID);
171     }
172 
173     /** Parses an XML representation and populates the BatteryUsageStats builder */
createFromXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)174     static void createFromXml(TypedXmlPullParser parser, BatteryUsageStats.Builder builder)
175             throws XmlPullParserException, IOException {
176         final int uid = parser.getAttributeInt(null, BatteryUsageStats.XML_ATTR_UID);
177         final UidBatteryConsumer.Builder consumerBuilder =
178                 builder.getOrCreateUidBatteryConsumerBuilder(uid);
179 
180         int eventType = parser.getEventType();
181         if (eventType != XmlPullParser.START_TAG
182                 || !parser.getName().equals(BatteryUsageStats.XML_TAG_UID)) {
183             throw new XmlPullParserException("Invalid XML parser state");
184         }
185 
186         consumerBuilder.setPackageWithHighestDrain(
187                 parser.getAttributeValue(null, BatteryUsageStats.XML_ATTR_HIGHEST_DRAIN_PACKAGE));
188         consumerBuilder.setTimeInStateMs(STATE_FOREGROUND,
189                 parser.getAttributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_FOREGROUND));
190         consumerBuilder.setTimeInStateMs(STATE_BACKGROUND,
191                 parser.getAttributeLong(null, BatteryUsageStats.XML_ATTR_TIME_IN_BACKGROUND));
192         while (!(eventType == XmlPullParser.END_TAG
193                 && parser.getName().equals(BatteryUsageStats.XML_TAG_UID))
194                 && eventType != XmlPullParser.END_DOCUMENT) {
195             if (eventType == XmlPullParser.START_TAG) {
196                 if (parser.getName().equals(BatteryUsageStats.XML_TAG_POWER_COMPONENTS)) {
197                     PowerComponents.parseXml(parser, consumerBuilder.mPowerComponentsBuilder);
198                 }
199             }
200             eventType = parser.next();
201         }
202     }
203 
204     /**
205      * Builder for UidBatteryConsumer.
206      */
207     public static final class Builder extends BaseBuilder<Builder> {
208         private static final String PACKAGE_NAME_UNINITIALIZED = "";
209         private final BatteryStats.Uid mBatteryStatsUid;
210         private final int mUid;
211         private String mPackageWithHighestDrain = PACKAGE_NAME_UNINITIALIZED;
212         public long mTimeInForegroundMs;
213         public long mTimeInBackgroundMs;
214         private boolean mExcludeFromBatteryUsageStats;
215 
Builder(@onNull String[] customPowerComponentNames, boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid)216         public Builder(@NonNull String[] customPowerComponentNames,
217                 boolean includePowerModels, @NonNull BatteryStats.Uid batteryStatsUid) {
218             super(customPowerComponentNames, includePowerModels);
219             mBatteryStatsUid = batteryStatsUid;
220             mUid = batteryStatsUid.getUid();
221         }
222 
Builder(@onNull String[] customPowerComponentNames, boolean includePowerModels, int uid)223         public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels,
224                 int uid) {
225             super(customPowerComponentNames, includePowerModels);
226             mBatteryStatsUid = null;
227             mUid = uid;
228         }
229 
230         @NonNull
getBatteryStatsUid()231         public BatteryStats.Uid getBatteryStatsUid() {
232             if (mBatteryStatsUid == null) {
233                 throw new IllegalStateException(
234                         "UidBatteryConsumer.Builder was initialized without a BatteryStats.Uid");
235             }
236             return mBatteryStatsUid;
237         }
238 
getUid()239         public int getUid() {
240             return mUid;
241         }
242 
243         /**
244          * Sets the name of the package owned by this UID that consumed the highest amount
245          * of power since BatteryStats reset.
246          */
247         @NonNull
setPackageWithHighestDrain(@ullable String packageName)248         public Builder setPackageWithHighestDrain(@Nullable String packageName) {
249             mPackageWithHighestDrain = TextUtils.nullIfEmpty(packageName);
250             return this;
251         }
252 
253         /**
254          * Sets the duration, in milliseconds, that this UID was active in a particular state,
255          * such as foreground or background.
256          */
257         @NonNull
setTimeInStateMs(@tate int state, long timeInStateMs)258         public Builder setTimeInStateMs(@State int state, long timeInStateMs) {
259             switch (state) {
260                 case STATE_FOREGROUND:
261                     mTimeInForegroundMs = timeInStateMs;
262                     break;
263                 case STATE_BACKGROUND:
264                     mTimeInBackgroundMs = timeInStateMs;
265                     break;
266                 default:
267                     throw new IllegalArgumentException("Unsupported state: " + state);
268             }
269             return this;
270         }
271 
272         /**
273          * Marks the UidBatteryConsumer for exclusion from the result set.
274          */
excludeFromBatteryUsageStats()275         public Builder excludeFromBatteryUsageStats() {
276             mExcludeFromBatteryUsageStats = true;
277             return this;
278         }
279 
280         /**
281          * Adds power and usage duration from the supplied UidBatteryConsumer.
282          */
add(UidBatteryConsumer consumer)283         public Builder add(UidBatteryConsumer consumer) {
284             mPowerComponentsBuilder.addPowerAndDuration(consumer.mPowerComponents);
285             mTimeInBackgroundMs += consumer.mTimeInBackgroundMs;
286             mTimeInForegroundMs += consumer.mTimeInForegroundMs;
287 
288             if (mPackageWithHighestDrain == PACKAGE_NAME_UNINITIALIZED) {
289                 mPackageWithHighestDrain = consumer.mPackageWithHighestDrain;
290             } else if (!TextUtils.equals(mPackageWithHighestDrain,
291                     consumer.mPackageWithHighestDrain)) {
292                 // Consider combining two UidBatteryConsumers with this distribution
293                 // of power drain between packages:
294                 // (package1=100, package2=10) and (package1=100, package2=101).
295                 // Since we don't know the actual power distribution between packages at this
296                 // point, we have no way to correctly declare package1 as the winner.
297                 // The naive logic of picking the consumer with the higher total consumed
298                 // power would produce an incorrect result.
299                 mPackageWithHighestDrain = null;
300             }
301             return this;
302         }
303 
304         /**
305          * Returns true if this UidBatteryConsumer must be excluded from the
306          * BatteryUsageStats.
307          */
isExcludedFromBatteryUsageStats()308         public boolean isExcludedFromBatteryUsageStats() {
309             return mExcludeFromBatteryUsageStats;
310         }
311 
312         /**
313          * Creates a read-only object out of the Builder values.
314          */
315         @NonNull
build()316         public UidBatteryConsumer build() {
317             if (mPackageWithHighestDrain == PACKAGE_NAME_UNINITIALIZED) {
318                 mPackageWithHighestDrain = null;
319             }
320             return new UidBatteryConsumer(this);
321         }
322     }
323 }
324