• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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