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