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