• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 package com.android.settings.fuelgauge;
15 
16 import android.content.ContentValues;
17 import android.database.Cursor;
18 import android.os.BatteryConsumer;
19 import android.util.Log;
20 
21 import java.time.Duration;
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     public static final String KEY_USER_ID = "userId";
31     public static final String KEY_APP_LABEL = "appLabel";
32     public static final String KEY_PACKAGE_NAME = "packageName";
33     public static final String KEY_IS_HIDDEN = "isHidden";
34     // Device booting elapsed time from SystemClock.elapsedRealtime().
35     public static final String KEY_BOOT_TIMESTAMP = "bootTimestamp";
36     public static final String KEY_TIMESTAMP = "timestamp";
37     public static final String KEY_ZONE_ID = "zoneId";
38     public static final String KEY_TOTAL_POWER = "totalPower";
39     public static final String KEY_CONSUME_POWER = "consumePower";
40     public static final String KEY_PERCENT_OF_TOTAL = "percentOfTotal";
41     public static final String KEY_FOREGROUND_USAGE_TIME = "foregroundUsageTimeInMs";
42     public static final String KEY_BACKGROUND_USAGE_TIME = "backgroundUsageTimeInMs";
43     public static final String KEY_DRAIN_TYPE = "drainType";
44     public static final String KEY_CONSUMER_TYPE = "consumerType";
45     public static final String KEY_BATTERY_LEVEL = "batteryLevel";
46     public static final String KEY_BATTERY_STATUS = "batteryStatus";
47     public static final String KEY_BATTERY_HEALTH = "batteryHealth";
48 
49     public final long mUid;
50     public final long mUserId;
51     public final String mAppLabel;
52     public final String mPackageName;
53     // Whether the data is represented as system component or not?
54     public final boolean mIsHidden;
55     // Records the timestamp relative information.
56     public final long mBootTimestamp;
57     public final long mTimestamp;
58     public final String mZoneId;
59     // Records the battery usage relative information.
60     public final double mTotalPower;
61     public final double mConsumePower;
62     public final double mPercentOfTotal;
63     public final long mForegroundUsageTimeInMs;
64     public final long mBackgroundUsageTimeInMs;
65     @BatteryConsumer.PowerComponent
66     public final int mDrainType;
67     @ConvertUtils.ConsumerType
68     public final int mConsumerType;
69     // Records the battery intent relative information.
70     public final int mBatteryLevel;
71     public final int mBatteryStatus;
72     public final int mBatteryHealth;
73 
74     private String mKey = null;
75     private boolean mIsValidEntry = true;
76 
BatteryHistEntry(ContentValues values)77     public BatteryHistEntry(ContentValues values) {
78         mUid = getLong(values, KEY_UID);
79         mUserId = getLong(values, KEY_USER_ID);
80         mAppLabel = getString(values, KEY_APP_LABEL);
81         mPackageName = getString(values, KEY_PACKAGE_NAME);
82         mIsHidden = getBoolean(values, KEY_IS_HIDDEN);
83         mBootTimestamp = getLong(values, KEY_BOOT_TIMESTAMP);
84         mTimestamp = getLong(values, KEY_TIMESTAMP);
85         mZoneId = getString(values, KEY_ZONE_ID);
86         mTotalPower = getDouble(values, KEY_TOTAL_POWER);
87         mConsumePower = getDouble(values, KEY_CONSUME_POWER);
88         mPercentOfTotal = getDouble(values, KEY_PERCENT_OF_TOTAL);
89         mForegroundUsageTimeInMs = getLong(values, KEY_FOREGROUND_USAGE_TIME);
90         mBackgroundUsageTimeInMs = getLong(values, KEY_BACKGROUND_USAGE_TIME);
91         mDrainType = getInteger(values, KEY_DRAIN_TYPE);
92         mConsumerType = getInteger(values, KEY_CONSUMER_TYPE);
93         mBatteryLevel = getInteger(values, KEY_BATTERY_LEVEL);
94         mBatteryStatus = getInteger(values, KEY_BATTERY_STATUS);
95         mBatteryHealth = getInteger(values, KEY_BATTERY_HEALTH);
96     }
97 
BatteryHistEntry(Cursor cursor)98     public BatteryHistEntry(Cursor cursor) {
99         mUid = getLong(cursor, KEY_UID);
100         mUserId = getLong(cursor, KEY_USER_ID);
101         mAppLabel = getString(cursor, KEY_APP_LABEL);
102         mPackageName = getString(cursor, KEY_PACKAGE_NAME);
103         mIsHidden = getBoolean(cursor, KEY_IS_HIDDEN);
104         mBootTimestamp = getLong(cursor, KEY_BOOT_TIMESTAMP);
105         mTimestamp = getLong(cursor, KEY_TIMESTAMP);
106         mZoneId = getString(cursor, KEY_ZONE_ID);
107         mTotalPower = getDouble(cursor, KEY_TOTAL_POWER);
108         mConsumePower = getDouble(cursor, KEY_CONSUME_POWER);
109         mPercentOfTotal = getDouble(cursor, KEY_PERCENT_OF_TOTAL);
110         mForegroundUsageTimeInMs = getLong(cursor, KEY_FOREGROUND_USAGE_TIME);
111         mBackgroundUsageTimeInMs = getLong(cursor, KEY_BACKGROUND_USAGE_TIME);
112         mDrainType = getInteger(cursor, KEY_DRAIN_TYPE);
113         mConsumerType = getInteger(cursor, KEY_CONSUMER_TYPE);
114         mBatteryLevel = getInteger(cursor, KEY_BATTERY_LEVEL);
115         mBatteryStatus = getInteger(cursor, KEY_BATTERY_STATUS);
116         mBatteryHealth = getInteger(cursor, KEY_BATTERY_HEALTH);
117     }
118 
BatteryHistEntry( BatteryHistEntry fromEntry, long bootTimestamp, long timestamp, double totalPower, double consumePower, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs, int batteryLevel)119     private BatteryHistEntry(
120           BatteryHistEntry fromEntry,
121           long bootTimestamp,
122           long timestamp,
123           double totalPower,
124           double consumePower,
125           long foregroundUsageTimeInMs,
126           long backgroundUsageTimeInMs,
127           int batteryLevel) {
128         mUid = fromEntry.mUid;
129         mUserId = fromEntry.mUserId;
130         mAppLabel = fromEntry.mAppLabel;
131         mPackageName = fromEntry.mPackageName;
132         mIsHidden = fromEntry.mIsHidden;
133         mBootTimestamp = bootTimestamp;
134         mTimestamp = timestamp;
135         mZoneId = fromEntry.mZoneId;
136         mTotalPower = totalPower;
137         mConsumePower = consumePower;
138         mPercentOfTotal = fromEntry.mPercentOfTotal;
139         mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
140         mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
141         mDrainType = fromEntry.mDrainType;
142         mConsumerType = fromEntry.mConsumerType;
143         mBatteryLevel = batteryLevel;
144         mBatteryStatus = fromEntry.mBatteryStatus;
145         mBatteryHealth = fromEntry.mBatteryHealth;
146     }
147 
148     /** Whether this {@link BatteryHistEntry} is valid or not? */
isValidEntry()149     public boolean isValidEntry() {
150         return mIsValidEntry;
151     }
152 
153     /** Whether this {@link BatteryHistEntry} is user consumer or not. */
isUserEntry()154     public boolean isUserEntry() {
155         return mConsumerType == ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
156     }
157 
158     /** Whether this {@link BatteryHistEntry} is app consumer or not. */
isAppEntry()159     public boolean isAppEntry() {
160         return mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
161     }
162 
163     /** Whether this {@link BatteryHistEntry} is system consumer or not. */
isSystemEntry()164     public boolean isSystemEntry() {
165         return mConsumerType == ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
166     }
167 
168     /** Gets an identifier to represent this {@link BatteryHistEntry}. */
getKey()169     public String getKey() {
170         if (mKey == null) {
171             switch (mConsumerType) {
172                 case ConvertUtils.CONSUMER_TYPE_UID_BATTERY:
173                     mKey = Long.toString(mUid);
174                     break;
175                 case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
176                     mKey = "S|" + mDrainType;
177                     break;
178                 case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
179                     mKey = "U|" + mUserId;
180                     break;
181             }
182         }
183         return mKey;
184     }
185 
186     @Override
toString()187     public String toString() {
188         final String recordAtDateTime =
189             ConvertUtils.utcToLocalTime(/*context=*/ null, mTimestamp);
190         final StringBuilder builder = new StringBuilder()
191             .append("\nBatteryHistEntry{")
192             .append(String.format("\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b",
193                   mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
194             .append(String.format("\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
195                   recordAtDateTime, mZoneId, Duration.ofMillis(mBootTimestamp).getSeconds()))
196             .append(String.format("\n\tusage=%f|total=%f|consume=%f|elapsedTime=%d|%d",
197                   mPercentOfTotal, mTotalPower, mConsumePower,
198                   Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
199                   Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
200             .append(String.format("\n\tdrainType=%d|consumerType=%d",
201                   mDrainType, mConsumerType))
202             .append(String.format("\n\tbattery=%d|status=%d|health=%d\n}",
203                   mBatteryLevel, mBatteryStatus, mBatteryHealth));
204         return builder.toString();
205     }
206 
getInteger(ContentValues values, String key)207     private int getInteger(ContentValues values, String key) {
208         if (values != null && values.containsKey(key)) {
209             return values.getAsInteger(key);
210         };
211         mIsValidEntry = false;
212         return 0;
213     }
214 
getInteger(Cursor cursor, String key)215     private int getInteger(Cursor cursor, String key) {
216         final int columnIndex = cursor.getColumnIndex(key);
217         if (columnIndex >= 0) {
218             return cursor.getInt(columnIndex);
219         }
220         mIsValidEntry = false;
221         return 0;
222     }
223 
getLong(ContentValues values, String key)224     private long getLong(ContentValues values, String key) {
225         if (values != null && values.containsKey(key)) {
226             return values.getAsLong(key);
227         }
228         mIsValidEntry = false;
229         return 0L;
230     }
231 
getLong(Cursor cursor, String key)232     private long getLong(Cursor cursor, String key) {
233         final int columnIndex = cursor.getColumnIndex(key);
234         if (columnIndex >= 0) {
235             return cursor.getLong(columnIndex);
236         }
237         mIsValidEntry = false;
238         return 0L;
239     }
240 
getDouble(ContentValues values, String key)241     private double getDouble(ContentValues values, String key) {
242         if (values != null && values.containsKey(key)) {
243             return values.getAsDouble(key);
244         }
245         mIsValidEntry = false;
246         return 0f;
247     }
248 
getDouble(Cursor cursor, String key)249     private double getDouble(Cursor cursor, String key) {
250         final int columnIndex = cursor.getColumnIndex(key);
251         if (columnIndex >= 0) {
252             return cursor.getDouble(columnIndex);
253         }
254         mIsValidEntry = false;
255         return 0f;
256     }
257 
getString(ContentValues values, String key)258     private String getString(ContentValues values, String key) {
259         if (values != null && values.containsKey(key)) {
260             return values.getAsString(key);
261         }
262         mIsValidEntry = false;
263         return null;
264     }
265 
getString(Cursor cursor, String key)266     private String getString(Cursor cursor, String key) {
267         final int columnIndex = cursor.getColumnIndex(key);
268         if (columnIndex >= 0) {
269             return cursor.getString(columnIndex);
270         }
271         mIsValidEntry = false;
272         return null;
273     }
274 
getBoolean(ContentValues values, String key)275     private boolean getBoolean(ContentValues values, String key) {
276         if (values != null && values.containsKey(key)) {
277             return values.getAsBoolean(key);
278         }
279         mIsValidEntry = false;
280         return false;
281     }
282 
getBoolean(Cursor cursor, String key)283     private boolean getBoolean(Cursor cursor, String key) {
284         final int columnIndex = cursor.getColumnIndex(key);
285         if (columnIndex >= 0) {
286             // Use value == 1 to represent boolean value in the database.
287             return cursor.getInt(columnIndex) == 1;
288         }
289         mIsValidEntry = false;
290         return false;
291     }
292 
293     /** Creates new {@link BatteryHistEntry} from interpolation. */
interpolate( long slotTimestamp, long upperTimestamp, double ratio, BatteryHistEntry lowerHistEntry, BatteryHistEntry upperHistEntry)294     public static BatteryHistEntry interpolate(
295             long slotTimestamp,
296             long upperTimestamp,
297             double ratio,
298             BatteryHistEntry lowerHistEntry,
299             BatteryHistEntry upperHistEntry) {
300         final double totalPower = interpolate(
301             lowerHistEntry == null ? 0 : lowerHistEntry.mTotalPower,
302             upperHistEntry.mTotalPower,
303             ratio);
304         final double consumePower = interpolate(
305             lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower,
306             upperHistEntry.mConsumePower,
307             ratio);
308         final double foregroundUsageTimeInMs = interpolate(
309             lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs,
310             upperHistEntry.mForegroundUsageTimeInMs,
311             ratio);
312         final double backgroundUsageTimeInMs = interpolate(
313             lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs,
314             upperHistEntry.mBackgroundUsageTimeInMs,
315             ratio);
316         // Checks whether there is any abnoaml cases!
317         if (upperHistEntry.mConsumePower < consumePower
318                 || upperHistEntry.mForegroundUsageTimeInMs < foregroundUsageTimeInMs
319                 || upperHistEntry.mBackgroundUsageTimeInMs < backgroundUsageTimeInMs) {
320             if (DEBUG) {
321                 Log.w(TAG, String.format(
322                         "abnormal interpolation:\nupper:%s\nlower:%s",
323                         upperHistEntry, lowerHistEntry));
324             }
325         }
326         final double batteryLevel =
327             lowerHistEntry == null
328                 ? upperHistEntry.mBatteryLevel
329                 : interpolate(
330                     lowerHistEntry.mBatteryLevel,
331                     upperHistEntry.mBatteryLevel,
332                     ratio);
333         return new BatteryHistEntry(
334             upperHistEntry,
335             /*bootTimestamp=*/ upperHistEntry.mBootTimestamp
336                 - (upperTimestamp - slotTimestamp),
337             /*timestamp=*/ slotTimestamp,
338             totalPower,
339             consumePower,
340             Math.round(foregroundUsageTimeInMs),
341             Math.round(backgroundUsageTimeInMs),
342             (int) Math.round(batteryLevel));
343     }
344 
interpolate(double v1, double v2, double ratio)345     private static double interpolate(double v1, double v2, double ratio) {
346         return v1 + ratio * (v2 - v1);
347     }
348 }
349