1 /* 2 * Copyright (C) 2022 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 com.android.settings.fuelgauge.batteryusage; 17 18 import android.content.ContentValues; 19 import android.database.Cursor; 20 import android.os.BatteryConsumer; 21 import android.util.Log; 22 23 import java.time.Duration; 24 25 /** A container class to carry data from {@link ContentValues}. */ 26 public class BatteryHistEntry { 27 private static final boolean DEBUG = false; 28 private static final String TAG = "BatteryHistEntry"; 29 30 /** Keys for accessing {@link ContentValues} or {@link Cursor}. */ 31 public static final String KEY_UID = "uid"; 32 public static final String KEY_USER_ID = "userId"; 33 public static final String KEY_PACKAGE_NAME = "packageName"; 34 public static final String KEY_TIMESTAMP = "timestamp"; 35 public static final String KEY_CONSUMER_TYPE = "consumerType"; 36 public static final String KEY_IS_FULL_CHARGE_CYCLE_START = "isFullChargeCycleStart"; 37 public static final String KEY_BATTERY_INFORMATION = "batteryInformation"; 38 public static final String KEY_BATTERY_INFORMATION_DEBUG = "batteryInformationDebug"; 39 40 public final long mUid; 41 public final long mUserId; 42 public final String mAppLabel; 43 public final String mPackageName; 44 // Whether the data is represented as system component or not? 45 public final boolean mIsHidden; 46 // Records the timestamp relative information. 47 public final long mBootTimestamp; 48 public final long mTimestamp; 49 public final String mZoneId; 50 // Records the battery usage relative information. 51 public final double mTotalPower; 52 public final double mConsumePower; 53 public final double mForegroundUsageConsumePower; 54 public final double mForegroundServiceUsageConsumePower; 55 public final double mBackgroundUsageConsumePower; 56 public final double mCachedUsageConsumePower; 57 public final double mPercentOfTotal; 58 public final long mForegroundUsageTimeInMs; 59 public final long mBackgroundUsageTimeInMs; 60 @BatteryConsumer.PowerComponent 61 public final int mDrainType; 62 @ConvertUtils.ConsumerType 63 public final int mConsumerType; 64 // Records the battery intent relative information. 65 public final int mBatteryLevel; 66 public final int mBatteryStatus; 67 public final int mBatteryHealth; 68 69 private String mKey = null; 70 private boolean mIsValidEntry = true; 71 BatteryHistEntry(ContentValues values)72 public BatteryHistEntry(ContentValues values) { 73 mUid = getLong(values, KEY_UID); 74 mUserId = getLong(values, KEY_USER_ID); 75 mPackageName = getString(values, KEY_PACKAGE_NAME); 76 mTimestamp = getLong(values, KEY_TIMESTAMP); 77 mConsumerType = getInteger(values, KEY_CONSUMER_TYPE); 78 final BatteryInformation batteryInformation = 79 ConvertUtils.getBatteryInformation(values, KEY_BATTERY_INFORMATION); 80 mAppLabel = batteryInformation.getAppLabel(); 81 mIsHidden = batteryInformation.getIsHidden(); 82 mBootTimestamp = batteryInformation.getBootTimestamp(); 83 mZoneId = batteryInformation.getZoneId(); 84 mTotalPower = batteryInformation.getTotalPower(); 85 mConsumePower = batteryInformation.getConsumePower(); 86 mForegroundUsageConsumePower = batteryInformation.getForegroundUsageConsumePower(); 87 mForegroundServiceUsageConsumePower = 88 batteryInformation.getForegroundServiceUsageConsumePower(); 89 mBackgroundUsageConsumePower = batteryInformation.getBackgroundUsageConsumePower(); 90 mCachedUsageConsumePower = batteryInformation.getCachedUsageConsumePower(); 91 mPercentOfTotal = batteryInformation.getPercentOfTotal(); 92 mForegroundUsageTimeInMs = batteryInformation.getForegroundUsageTimeInMs(); 93 mBackgroundUsageTimeInMs = batteryInformation.getBackgroundUsageTimeInMs(); 94 mDrainType = batteryInformation.getDrainType(); 95 final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState(); 96 mBatteryLevel = deviceBatteryState.getBatteryLevel(); 97 mBatteryStatus = deviceBatteryState.getBatteryStatus(); 98 mBatteryHealth = deviceBatteryState.getBatteryHealth(); 99 } 100 BatteryHistEntry(Cursor cursor)101 public BatteryHistEntry(Cursor cursor) { 102 mUid = getLong(cursor, KEY_UID); 103 mUserId = getLong(cursor, KEY_USER_ID); 104 mPackageName = getString(cursor, KEY_PACKAGE_NAME); 105 mTimestamp = getLong(cursor, KEY_TIMESTAMP); 106 mConsumerType = getInteger(cursor, KEY_CONSUMER_TYPE); 107 final BatteryInformation batteryInformation = 108 ConvertUtils.getBatteryInformation(cursor, KEY_BATTERY_INFORMATION); 109 mAppLabel = batteryInformation.getAppLabel(); 110 mIsHidden = batteryInformation.getIsHidden(); 111 mBootTimestamp = batteryInformation.getBootTimestamp(); 112 mZoneId = batteryInformation.getZoneId(); 113 mTotalPower = batteryInformation.getTotalPower(); 114 mConsumePower = batteryInformation.getConsumePower(); 115 mForegroundUsageConsumePower = batteryInformation.getForegroundUsageConsumePower(); 116 mForegroundServiceUsageConsumePower = 117 batteryInformation.getForegroundServiceUsageConsumePower(); 118 mBackgroundUsageConsumePower = batteryInformation.getBackgroundUsageConsumePower(); 119 mCachedUsageConsumePower = batteryInformation.getCachedUsageConsumePower(); 120 mPercentOfTotal = batteryInformation.getPercentOfTotal(); 121 mForegroundUsageTimeInMs = batteryInformation.getForegroundUsageTimeInMs(); 122 mBackgroundUsageTimeInMs = batteryInformation.getBackgroundUsageTimeInMs(); 123 mDrainType = batteryInformation.getDrainType(); 124 final DeviceBatteryState deviceBatteryState = batteryInformation.getDeviceBatteryState(); 125 mBatteryLevel = deviceBatteryState.getBatteryLevel(); 126 mBatteryStatus = deviceBatteryState.getBatteryStatus(); 127 mBatteryHealth = deviceBatteryState.getBatteryHealth(); 128 } 129 BatteryHistEntry( BatteryHistEntry fromEntry, long bootTimestamp, long timestamp, double totalPower, double consumePower, double foregroundUsageConsumePower, double foregroundServiceUsageConsumePower, double backgroundUsageConsumePower, double cachedUsageConsumePower, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs, int batteryLevel)130 private BatteryHistEntry( 131 BatteryHistEntry fromEntry, 132 long bootTimestamp, 133 long timestamp, 134 double totalPower, 135 double consumePower, 136 double foregroundUsageConsumePower, 137 double foregroundServiceUsageConsumePower, 138 double backgroundUsageConsumePower, 139 double cachedUsageConsumePower, 140 long foregroundUsageTimeInMs, 141 long backgroundUsageTimeInMs, 142 int batteryLevel) { 143 mUid = fromEntry.mUid; 144 mUserId = fromEntry.mUserId; 145 mAppLabel = fromEntry.mAppLabel; 146 mPackageName = fromEntry.mPackageName; 147 mIsHidden = fromEntry.mIsHidden; 148 mBootTimestamp = bootTimestamp; 149 mTimestamp = timestamp; 150 mZoneId = fromEntry.mZoneId; 151 mTotalPower = totalPower; 152 mConsumePower = consumePower; 153 mForegroundUsageConsumePower = foregroundUsageConsumePower; 154 mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower; 155 mBackgroundUsageConsumePower = backgroundUsageConsumePower; 156 mCachedUsageConsumePower = cachedUsageConsumePower; 157 mPercentOfTotal = fromEntry.mPercentOfTotal; 158 mForegroundUsageTimeInMs = foregroundUsageTimeInMs; 159 mBackgroundUsageTimeInMs = backgroundUsageTimeInMs; 160 mDrainType = fromEntry.mDrainType; 161 mConsumerType = fromEntry.mConsumerType; 162 mBatteryLevel = batteryLevel; 163 mBatteryStatus = fromEntry.mBatteryStatus; 164 mBatteryHealth = fromEntry.mBatteryHealth; 165 } 166 167 /** Whether this {@link BatteryHistEntry} is valid or not? */ isValidEntry()168 public boolean isValidEntry() { 169 return mIsValidEntry; 170 } 171 172 /** Gets an identifier to represent this {@link BatteryHistEntry}. */ getKey()173 public String getKey() { 174 if (mKey == null) { 175 switch (mConsumerType) { 176 case ConvertUtils.CONSUMER_TYPE_UID_BATTERY: 177 mKey = Long.toString(mUid); 178 break; 179 case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY: 180 mKey = "S|" + mDrainType; 181 break; 182 case ConvertUtils.CONSUMER_TYPE_USER_BATTERY: 183 mKey = "U|" + mUserId; 184 break; 185 } 186 } 187 return mKey; 188 } 189 190 @Override toString()191 public String toString() { 192 final String recordAtDateTime = ConvertUtils.utcToLocalTimeForLogging(mTimestamp); 193 final StringBuilder builder = new StringBuilder() 194 .append("\nBatteryHistEntry{") 195 .append(String.format("\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b", 196 mPackageName, mAppLabel, mUid, mUserId, mIsHidden)) 197 .append(String.format("\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d", 198 recordAtDateTime, mZoneId, Duration.ofMillis(mBootTimestamp).getSeconds())) 199 .append(String.format("\n\tusage=%f|total=%f|consume=%f", 200 mPercentOfTotal, mTotalPower, mConsumePower)) 201 .append(String.format("\n\tforeground=%f|foregroundService=%f", 202 mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower)) 203 .append(String.format("\n\tbackground=%f|cached=%f", 204 mBackgroundUsageConsumePower, mCachedUsageConsumePower)) 205 .append(String.format("\n\telapsedTime=%d|%d", 206 Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(), 207 Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds())) 208 .append(String.format("\n\tdrainType=%d|consumerType=%d", 209 mDrainType, mConsumerType)) 210 .append(String.format("\n\tbattery=%d|status=%d|health=%d\n}", 211 mBatteryLevel, mBatteryStatus, mBatteryHealth)); 212 return builder.toString(); 213 } 214 getInteger(ContentValues values, String key)215 private int getInteger(ContentValues values, String key) { 216 if (values != null && values.containsKey(key)) { 217 return values.getAsInteger(key); 218 } 219 mIsValidEntry = false; 220 return 0; 221 } 222 getInteger(Cursor cursor, String key)223 private int getInteger(Cursor cursor, String key) { 224 final int columnIndex = cursor.getColumnIndex(key); 225 if (columnIndex >= 0) { 226 return cursor.getInt(columnIndex); 227 } 228 mIsValidEntry = false; 229 return 0; 230 } 231 getLong(ContentValues values, String key)232 private long getLong(ContentValues values, String key) { 233 if (values != null && values.containsKey(key)) { 234 return values.getAsLong(key); 235 } 236 mIsValidEntry = false; 237 return 0L; 238 } 239 getLong(Cursor cursor, String key)240 private long getLong(Cursor cursor, String key) { 241 final int columnIndex = cursor.getColumnIndex(key); 242 if (columnIndex >= 0) { 243 return cursor.getLong(columnIndex); 244 } 245 mIsValidEntry = false; 246 return 0L; 247 } 248 getString(ContentValues values, String key)249 private String getString(ContentValues values, String key) { 250 if (values != null && values.containsKey(key)) { 251 return values.getAsString(key); 252 } 253 mIsValidEntry = false; 254 return null; 255 } 256 getString(Cursor cursor, String key)257 private String getString(Cursor cursor, String key) { 258 final int columnIndex = cursor.getColumnIndex(key); 259 if (columnIndex >= 0) { 260 return cursor.getString(columnIndex); 261 } 262 mIsValidEntry = false; 263 return null; 264 } 265 266 /** Creates new {@link BatteryHistEntry} from interpolation. */ interpolate( long slotTimestamp, long upperTimestamp, double ratio, BatteryHistEntry lowerHistEntry, BatteryHistEntry upperHistEntry)267 public static BatteryHistEntry interpolate( 268 long slotTimestamp, 269 long upperTimestamp, 270 double ratio, 271 BatteryHistEntry lowerHistEntry, 272 BatteryHistEntry upperHistEntry) { 273 final double totalPower = interpolate( 274 lowerHistEntry == null ? 0 : lowerHistEntry.mTotalPower, 275 upperHistEntry.mTotalPower, 276 ratio); 277 final double consumePower = interpolate( 278 lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower, 279 upperHistEntry.mConsumePower, 280 ratio); 281 final double foregroundUsageConsumePower = interpolate( 282 lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageConsumePower, 283 upperHistEntry.mForegroundUsageConsumePower, 284 ratio); 285 final double foregroundServiceUsageConsumePower = interpolate( 286 lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundServiceUsageConsumePower, 287 upperHistEntry.mForegroundServiceUsageConsumePower, 288 ratio); 289 final double backgroundUsageConsumePower = interpolate( 290 lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageConsumePower, 291 upperHistEntry.mBackgroundUsageConsumePower, 292 ratio); 293 final double cachedUsageConsumePower = interpolate( 294 lowerHistEntry == null ? 0 : lowerHistEntry.mCachedUsageConsumePower, 295 upperHistEntry.mCachedUsageConsumePower, 296 ratio); 297 final double foregroundUsageTimeInMs = interpolate( 298 (double) (lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs), 299 (double) upperHistEntry.mForegroundUsageTimeInMs, 300 ratio); 301 final double backgroundUsageTimeInMs = interpolate( 302 (double) (lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs), 303 (double) upperHistEntry.mBackgroundUsageTimeInMs, 304 ratio); 305 // Checks whether there is any abnormal cases! 306 if (upperHistEntry.mConsumePower < consumePower 307 || upperHistEntry.mForegroundUsageConsumePower < foregroundUsageConsumePower 308 || upperHistEntry.mForegroundServiceUsageConsumePower 309 < foregroundServiceUsageConsumePower 310 || upperHistEntry.mBackgroundUsageConsumePower < backgroundUsageConsumePower 311 || upperHistEntry.mCachedUsageConsumePower < cachedUsageConsumePower 312 || upperHistEntry.mForegroundUsageTimeInMs < foregroundUsageTimeInMs 313 || upperHistEntry.mBackgroundUsageTimeInMs < backgroundUsageTimeInMs) { 314 if (DEBUG) { 315 Log.w(TAG, String.format( 316 "abnormal interpolation:\nupper:%s\nlower:%s", 317 upperHistEntry, lowerHistEntry)); 318 } 319 } 320 final double batteryLevel = 321 lowerHistEntry == null 322 ? upperHistEntry.mBatteryLevel 323 : interpolate( 324 lowerHistEntry.mBatteryLevel, 325 upperHistEntry.mBatteryLevel, 326 ratio); 327 return new BatteryHistEntry( 328 upperHistEntry, 329 /*bootTimestamp=*/ upperHistEntry.mBootTimestamp 330 - (upperTimestamp - slotTimestamp), 331 /*timestamp=*/ slotTimestamp, 332 totalPower, 333 consumePower, 334 foregroundUsageConsumePower, 335 foregroundServiceUsageConsumePower, 336 backgroundUsageConsumePower, 337 cachedUsageConsumePower, 338 Math.round(foregroundUsageTimeInMs), 339 Math.round(backgroundUsageTimeInMs), 340 (int) Math.round(batteryLevel)); 341 } 342 interpolate(double v1, double v2, double ratio)343 private static double interpolate(double v1, double v2, double ratio) { 344 return v1 + ratio * (v2 - v1); 345 } 346 } 347