blob: ead98e7eee3ca5524e895234e3776c59e5ce6217 [file] [log] [blame]
Dianne Hackborna7c837f2014-01-15 16:20:44 -08001/*
2 * Copyright (C) 2009 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
17package com.android.internal.os;
18
Mathew Inwoodc185f082018-08-20 14:28:54 +010019import android.annotation.UnsupportedAppUsage;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080020import android.content.Context;
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -070021import android.content.Intent;
22import android.content.IntentFilter;
jackqdyulei1424c1d2017-06-05 16:15:54 -070023import android.content.pm.PackageManager;
24import android.content.res.Resources;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080025import android.hardware.SensorManager;
26import android.net.ConnectivityManager;
27import android.os.BatteryStats;
28import android.os.BatteryStats.Uid;
29import android.os.Bundle;
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -070030import android.os.MemoryFile;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080031import android.os.Parcel;
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -070032import android.os.ParcelFileDescriptor;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080033import android.os.Process;
34import android.os.RemoteException;
Makoto Onuki9700015b2018-07-27 17:06:30 -070035import android.os.SELinux;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080036import android.os.ServiceManager;
37import android.os.SystemClock;
38import android.os.UserHandle;
jackqdyulei1424c1d2017-06-05 16:15:54 -070039import android.text.format.DateUtils;
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -070040import android.util.ArrayMap;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080041import android.util.Log;
42import android.util.SparseArray;
jackqdyulei1424c1d2017-06-05 16:15:54 -070043import android.util.SparseLongArray;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080044
jackqdyulei1424c1d2017-06-05 16:15:54 -070045import com.android.internal.annotations.VisibleForTesting;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080046import com.android.internal.app.IBatteryStats;
47import com.android.internal.os.BatterySipper.DrainType;
jackqdyulei1424c1d2017-06-05 16:15:54 -070048import com.android.internal.util.ArrayUtils;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080049
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -070050import java.io.File;
51import java.io.FileInputStream;
52import java.io.FileOutputStream;
53import java.io.IOException;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080054import java.util.ArrayList;
55import java.util.Collections;
Dianne Hackbornd45665b2014-02-26 12:35:32 -080056import java.util.Comparator;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080057import java.util.List;
Adam Lesinski8a83c612015-07-22 13:50:23 -070058import java.util.Locale;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080059
60/**
61 * A helper class for retrieving the power usage information for all applications and services.
62 *
63 * The caller must initialize this class as soon as activity object is ready to use (for example, in
64 * onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
65 */
jackqdyulei1424c1d2017-06-05 16:15:54 -070066public class BatteryStatsHelper {
Adam Lesinskie08af192015-03-25 16:42:59 -070067 static final boolean DEBUG = false;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080068
69 private static final String TAG = BatteryStatsHelper.class.getSimpleName();
70
71 private static BatteryStats sStatsXfer;
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -070072 private static Intent sBatteryBroadcastXfer;
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -070073 private static ArrayMap<File, BatteryStats> sFileXfer = new ArrayMap<>();
Dianne Hackborna7c837f2014-01-15 16:20:44 -080074
75 final private Context mContext;
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -070076 final private boolean mCollectBatteryBroadcast;
Dianne Hackbornd953c532014-08-16 18:17:38 -070077 final private boolean mWifiOnly;
Dianne Hackborna7c837f2014-01-15 16:20:44 -080078
Mathew Inwoodc185f082018-08-20 14:28:54 +010079 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -080080 private IBatteryStats mBatteryInfo;
81 private BatteryStats mStats;
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -070082 private Intent mBatteryBroadcast;
Mathew Inwoodc185f082018-08-20 14:28:54 +010083 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -080084 private PowerProfile mPowerProfile;
85
jackqdyulei1424c1d2017-06-05 16:15:54 -070086 private String[] mSystemPackageArray;
87 private String[] mServicepackageArray;
88 private PackageManager mPackageManager;
89
Adam Lesinskie08af192015-03-25 16:42:59 -070090 /**
91 * List of apps using power.
92 */
Mathew Inwoodc185f082018-08-20 14:28:54 +010093 @UnsupportedAppUsage
Adam Lesinskie08af192015-03-25 16:42:59 -070094 private final List<BatterySipper> mUsageList = new ArrayList<>();
Dianne Hackborna7c837f2014-01-15 16:20:44 -080095
Adam Lesinskie08af192015-03-25 16:42:59 -070096 /**
97 * List of apps using wifi power.
98 */
99 private final List<BatterySipper> mWifiSippers = new ArrayList<>();
100
101 /**
102 * List of apps using bluetooth power.
103 */
104 private final List<BatterySipper> mBluetoothSippers = new ArrayList<>();
105
106 private final SparseArray<List<BatterySipper>> mUserSippers = new SparseArray<>();
107
108 private final List<BatterySipper> mMobilemsppList = new ArrayList<>();
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800109
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800110 private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800111
Adam Lesinski76a267b2016-04-20 13:04:59 -0700112 long mRawRealtimeUs;
113 long mRawUptimeUs;
114 long mBatteryRealtimeUs;
115 long mBatteryUptimeUs;
116 long mTypeBatteryRealtimeUs;
117 long mTypeBatteryUptimeUs;
118 long mBatteryTimeRemainingUs;
119 long mChargeTimeRemainingUs;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800120
121 private long mStatsPeriod = 0;
Adam Lesinskie08af192015-03-25 16:42:59 -0700122
123 // The largest entry by power.
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800124 private double mMaxPower = 1;
Adam Lesinskie08af192015-03-25 16:42:59 -0700125
126 // The largest real entry by power (not undercounted or overcounted).
Dianne Hackbornfee756f2014-07-16 17:31:10 -0700127 private double mMaxRealPower = 1;
Adam Lesinskie08af192015-03-25 16:42:59 -0700128
129 // Total computed power.
Dianne Hackborn099bc622014-01-22 13:39:16 -0800130 private double mComputedPower;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800131 private double mTotalPower;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800132 private double mMinDrainedPower;
133 private double mMaxDrainedPower;
134
Adam Lesinskie08af192015-03-25 16:42:59 -0700135 PowerCalculator mCpuPowerCalculator;
136 PowerCalculator mWakelockPowerCalculator;
137 MobileRadioPowerCalculator mMobileRadioPowerCalculator;
138 PowerCalculator mWifiPowerCalculator;
139 PowerCalculator mBluetoothPowerCalculator;
140 PowerCalculator mSensorPowerCalculator;
Ruben Brunk5b1308f2015-06-03 18:49:27 -0700141 PowerCalculator mCameraPowerCalculator;
142 PowerCalculator mFlashlightPowerCalculator;
James Carr2dd7e5e2016-07-20 18:48:39 -0700143 PowerCalculator mMemoryPowerCalculator;
Mike Ma07305c02018-03-02 16:57:31 -0800144 PowerCalculator mMediaPowerCalculator;
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800145
Adam Lesinskic691d3c2015-07-28 17:11:29 -0700146 boolean mHasWifiPowerReporting = false;
147 boolean mHasBluetoothPowerReporting = false;
148
Adam Lesinskie08af192015-03-25 16:42:59 -0700149 public static boolean checkWifiOnly(Context context) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700150 ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
Adam Lesinskie08af192015-03-25 16:42:59 -0700151 Context.CONNECTIVITY_SERVICE);
Kweku Adams2f73ecd2017-09-27 16:59:19 -0700152 if (cm == null) {
153 return false;
154 }
Adam Lesinskie08af192015-03-25 16:42:59 -0700155 return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
156 }
157
Adam Lesinski17390762015-04-10 13:17:47 -0700158 public static boolean checkHasWifiPowerReporting(BatteryStats stats, PowerProfile profile) {
159 return stats.hasWifiActivityReporting() &&
160 profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE) != 0 &&
161 profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX) != 0 &&
162 profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX) != 0;
Adam Lesinskie08af192015-03-25 16:42:59 -0700163 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800164
Adam Lesinskie283d332015-04-16 12:29:25 -0700165 public static boolean checkHasBluetoothPowerReporting(BatteryStats stats,
jackqdyulei1424c1d2017-06-05 16:15:54 -0700166 PowerProfile profile) {
Adam Lesinskie283d332015-04-16 12:29:25 -0700167 return stats.hasBluetoothActivityReporting() &&
168 profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE) != 0 &&
169 profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX) != 0 &&
170 profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX) != 0;
171 }
172
Mathew Inwoodc185f082018-08-20 14:28:54 +0100173 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800174 public BatteryStatsHelper(Context context) {
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -0700175 this(context, true);
176 }
177
Mathew Inwoodc185f082018-08-20 14:28:54 +0100178 @UnsupportedAppUsage
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -0700179 public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
Adam Lesinskie08af192015-03-25 16:42:59 -0700180 this(context, collectBatteryBroadcast, checkWifiOnly(context));
Dianne Hackbornd953c532014-08-16 18:17:38 -0700181 }
182
Mathew Inwoodc185f082018-08-20 14:28:54 +0100183 @UnsupportedAppUsage
Dianne Hackbornd953c532014-08-16 18:17:38 -0700184 public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) {
185 mContext = context;
186 mCollectBatteryBroadcast = collectBatteryBroadcast;
187 mWifiOnly = wifiOnly;
jackqdyulei1424c1d2017-06-05 16:15:54 -0700188 mPackageManager = context.getPackageManager();
189
190 final Resources resources = context.getResources();
191 mSystemPackageArray = resources.getStringArray(
192 com.android.internal.R.array.config_batteryPackageTypeSystem);
193 mServicepackageArray = resources.getStringArray(
194 com.android.internal.R.array.config_batteryPackageTypeService);
Dianne Hackbornd953c532014-08-16 18:17:38 -0700195 }
196
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -0700197 public void storeStatsHistoryInFile(String fname) {
198 synchronized (sFileXfer) {
199 File path = makeFilePath(mContext, fname);
200 sFileXfer.put(path, this.getStats());
201 FileOutputStream fout = null;
202 try {
203 fout = new FileOutputStream(path);
204 Parcel hist = Parcel.obtain();
205 getStats().writeToParcelWithoutUids(hist, 0);
206 byte[] histData = hist.marshall();
207 fout.write(histData);
208 } catch (IOException e) {
209 Log.w(TAG, "Unable to write history to file", e);
210 } finally {
211 if (fout != null) {
212 try {
213 fout.close();
214 } catch (IOException e) {
215 }
216 }
217 }
218 }
219 }
220
221 public static BatteryStats statsFromFile(Context context, String fname) {
222 synchronized (sFileXfer) {
223 File path = makeFilePath(context, fname);
224 BatteryStats stats = sFileXfer.get(path);
225 if (stats != null) {
226 return stats;
227 }
228 FileInputStream fin = null;
229 try {
230 fin = new FileInputStream(path);
231 byte[] data = readFully(fin);
232 Parcel parcel = Parcel.obtain();
233 parcel.unmarshall(data, 0, data.length);
234 parcel.setDataPosition(0);
235 return com.android.internal.os.BatteryStatsImpl.CREATOR.createFromParcel(parcel);
236 } catch (IOException e) {
237 Log.w(TAG, "Unable to read history to file", e);
238 } finally {
239 if (fin != null) {
240 try {
241 fin.close();
242 } catch (IOException e) {
243 }
244 }
245 }
246 }
247 return getStats(IBatteryStats.Stub.asInterface(
jackqdyulei1424c1d2017-06-05 16:15:54 -0700248 ServiceManager.getService(BatteryStats.SERVICE_NAME)));
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -0700249 }
250
Mathew Inwoodc185f082018-08-20 14:28:54 +0100251 @UnsupportedAppUsage
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -0700252 public static void dropFile(Context context, String fname) {
253 makeFilePath(context, fname).delete();
254 }
255
256 private static File makeFilePath(Context context, String fname) {
257 return new File(context.getFilesDir(), fname);
258 }
259
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800260 /** Clears the current stats and forces recreating for future use. */
Mathew Inwoodc185f082018-08-20 14:28:54 +0100261 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800262 public void clearStats() {
263 mStats = null;
264 }
265
Mathew Inwoodc185f082018-08-20 14:28:54 +0100266 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800267 public BatteryStats getStats() {
268 if (mStats == null) {
269 load();
270 }
271 return mStats;
272 }
273
Mathew Inwoodc185f082018-08-20 14:28:54 +0100274 @UnsupportedAppUsage
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -0700275 public Intent getBatteryBroadcast() {
276 if (mBatteryBroadcast == null && mCollectBatteryBroadcast) {
277 load();
278 }
279 return mBatteryBroadcast;
280 }
281
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800282 public PowerProfile getPowerProfile() {
283 return mPowerProfile;
284 }
285
286 public void create(BatteryStats stats) {
287 mPowerProfile = new PowerProfile(mContext);
288 mStats = stats;
289 }
290
Mathew Inwoodc185f082018-08-20 14:28:54 +0100291 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800292 public void create(Bundle icicle) {
293 if (icicle != null) {
294 mStats = sStatsXfer;
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -0700295 mBatteryBroadcast = sBatteryBroadcastXfer;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800296 }
297 mBatteryInfo = IBatteryStats.Stub.asInterface(
298 ServiceManager.getService(BatteryStats.SERVICE_NAME));
299 mPowerProfile = new PowerProfile(mContext);
300 }
301
Mathew Inwoodc185f082018-08-20 14:28:54 +0100302 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800303 public void storeState() {
304 sStatsXfer = mStats;
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -0700305 sBatteryBroadcastXfer = mBatteryBroadcast;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800306 }
307
308 public static String makemAh(double power) {
Adam Lesinskie283d332015-04-16 12:29:25 -0700309 if (power == 0) return "0";
Adam Lesinski8a83c612015-07-22 13:50:23 -0700310
311 final String format;
jackqdyulei1424c1d2017-06-05 16:15:54 -0700312 if (power < .00001) {
313 format = "%.8f";
314 } else if (power < .0001) {
315 format = "%.7f";
316 } else if (power < .001) {
317 format = "%.6f";
318 } else if (power < .01) {
319 format = "%.5f";
320 } else if (power < .1) {
321 format = "%.4f";
322 } else if (power < 1) {
323 format = "%.3f";
324 } else if (power < 10) {
325 format = "%.2f";
326 } else if (power < 100) {
327 format = "%.1f";
328 } else {
329 format = "%.0f";
330 }
Adam Lesinski8a83c612015-07-22 13:50:23 -0700331
332 // Use English locale because this is never used in UI (only in checkin and dump).
333 return String.format(Locale.ENGLISH, format, power);
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800334 }
335
336 /**
337 * Refreshes the power usage list.
338 */
Mathew Inwoodc185f082018-08-20 14:28:54 +0100339 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800340 public void refreshStats(int statsType, int asUser) {
Adam Lesinskie08af192015-03-25 16:42:59 -0700341 SparseArray<UserHandle> users = new SparseArray<>(1);
Zoltan Szatmary-Banc3b07a02014-07-01 17:11:07 +0100342 users.put(asUser, new UserHandle(asUser));
343 refreshStats(statsType, users);
344 }
345
346 /**
347 * Refreshes the power usage list.
348 */
Mathew Inwoodc185f082018-08-20 14:28:54 +0100349 @UnsupportedAppUsage
Zoltan Szatmary-Banc3b07a02014-07-01 17:11:07 +0100350 public void refreshStats(int statsType, List<UserHandle> asUsers) {
351 final int n = asUsers.size();
Adam Lesinskie08af192015-03-25 16:42:59 -0700352 SparseArray<UserHandle> users = new SparseArray<>(n);
Zoltan Szatmary-Banc3b07a02014-07-01 17:11:07 +0100353 for (int i = 0; i < n; ++i) {
354 UserHandle userHandle = asUsers.get(i);
355 users.put(userHandle.getIdentifier(), userHandle);
356 }
357 refreshStats(statsType, users);
358 }
359
360 /**
361 * Refreshes the power usage list.
362 */
Mathew Inwoodc185f082018-08-20 14:28:54 +0100363 @UnsupportedAppUsage
Zoltan Szatmary-Banc3b07a02014-07-01 17:11:07 +0100364 public void refreshStats(int statsType, SparseArray<UserHandle> asUsers) {
365 refreshStats(statsType, asUsers, SystemClock.elapsedRealtime() * 1000,
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800366 SystemClock.uptimeMillis() * 1000);
367 }
368
Zoltan Szatmary-Banc3b07a02014-07-01 17:11:07 +0100369 public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs,
370 long rawUptimeUs) {
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800371 // Initialize mStats if necessary.
372 getStats();
373
374 mMaxPower = 0;
Dianne Hackbornfee756f2014-07-16 17:31:10 -0700375 mMaxRealPower = 0;
Dianne Hackborn099bc622014-01-22 13:39:16 -0800376 mComputedPower = 0;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800377 mTotalPower = 0;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800378
379 mUsageList.clear();
380 mWifiSippers.clear();
381 mBluetoothSippers.clear();
382 mUserSippers.clear();
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800383 mMobilemsppList.clear();
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800384
385 if (mStats == null) {
386 return;
387 }
388
Adam Lesinskie08af192015-03-25 16:42:59 -0700389 if (mCpuPowerCalculator == null) {
Adam Lesinski6832f392015-09-05 18:05:40 -0700390 mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
Adam Lesinskie08af192015-03-25 16:42:59 -0700391 }
392 mCpuPowerCalculator.reset();
393
James Carr2dd7e5e2016-07-20 18:48:39 -0700394 if (mMemoryPowerCalculator == null) {
395 mMemoryPowerCalculator = new MemoryPowerCalculator(mPowerProfile);
396 }
397 mMemoryPowerCalculator.reset();
398
Adam Lesinskie08af192015-03-25 16:42:59 -0700399 if (mWakelockPowerCalculator == null) {
400 mWakelockPowerCalculator = new WakelockPowerCalculator(mPowerProfile);
401 }
402 mWakelockPowerCalculator.reset();
403
404 if (mMobileRadioPowerCalculator == null) {
405 mMobileRadioPowerCalculator = new MobileRadioPowerCalculator(mPowerProfile, mStats);
406 }
407 mMobileRadioPowerCalculator.reset(mStats);
408
Adam Lesinskic691d3c2015-07-28 17:11:29 -0700409 // checkHasWifiPowerReporting can change if we get energy data at a later point, so
410 // always check this field.
411 final boolean hasWifiPowerReporting = checkHasWifiPowerReporting(mStats, mPowerProfile);
412 if (mWifiPowerCalculator == null || hasWifiPowerReporting != mHasWifiPowerReporting) {
413 mWifiPowerCalculator = hasWifiPowerReporting ?
414 new WifiPowerCalculator(mPowerProfile) :
415 new WifiPowerEstimator(mPowerProfile);
416 mHasWifiPowerReporting = hasWifiPowerReporting;
Adam Lesinskie08af192015-03-25 16:42:59 -0700417 }
418 mWifiPowerCalculator.reset();
419
Adam Lesinskic691d3c2015-07-28 17:11:29 -0700420 final boolean hasBluetoothPowerReporting = checkHasBluetoothPowerReporting(mStats,
jackqdyulei1424c1d2017-06-05 16:15:54 -0700421 mPowerProfile);
Adam Lesinskic691d3c2015-07-28 17:11:29 -0700422 if (mBluetoothPowerCalculator == null ||
423 hasBluetoothPowerReporting != mHasBluetoothPowerReporting) {
424 mBluetoothPowerCalculator = new BluetoothPowerCalculator(mPowerProfile);
425 mHasBluetoothPowerReporting = hasBluetoothPowerReporting;
Adam Lesinskie08af192015-03-25 16:42:59 -0700426 }
427 mBluetoothPowerCalculator.reset();
428
Hui Yu57f69322018-05-22 14:01:22 -0700429 mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile,
430 (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE),
431 mStats, rawRealtimeUs, statsType);
Adam Lesinskie08af192015-03-25 16:42:59 -0700432 mSensorPowerCalculator.reset();
433
Ruben Brunk5b1308f2015-06-03 18:49:27 -0700434 if (mCameraPowerCalculator == null) {
435 mCameraPowerCalculator = new CameraPowerCalculator(mPowerProfile);
436 }
437 mCameraPowerCalculator.reset();
438
439 if (mFlashlightPowerCalculator == null) {
440 mFlashlightPowerCalculator = new FlashlightPowerCalculator(mPowerProfile);
441 }
442 mFlashlightPowerCalculator.reset();
443
Mike Ma07305c02018-03-02 16:57:31 -0800444 if (mMediaPowerCalculator == null) {
445 mMediaPowerCalculator = new MediaPowerCalculator(mPowerProfile);
446 }
447 mMediaPowerCalculator.reset();
448
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800449 mStatsType = statsType;
Adam Lesinski76a267b2016-04-20 13:04:59 -0700450 mRawUptimeUs = rawUptimeUs;
451 mRawRealtimeUs = rawRealtimeUs;
452 mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
453 mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
454 mTypeBatteryUptimeUs = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
455 mTypeBatteryRealtimeUs = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
456 mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
457 mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800458
459 if (DEBUG) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700460 Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs / 1000) + " uptime="
461 + (rawUptimeUs / 1000));
462 Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtimeUs / 1000) + " uptime="
463 + (mBatteryUptimeUs / 1000));
464 Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtimeUs / 1000) + " uptime="
465 + (mTypeBatteryUptimeUs / 1000));
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800466 }
467 mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge()
468 * mPowerProfile.getBatteryCapacity()) / 100;
469 mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge()
470 * mPowerProfile.getBatteryCapacity()) / 100;
471
Zoltan Szatmary-Banc3b07a02014-07-01 17:11:07 +0100472 processAppUsage(asUsers);
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800473
474 // Before aggregating apps in to users, collect all apps to sort by their ms per packet.
jackqdyulei1424c1d2017-06-05 16:15:54 -0700475 for (int i = 0; i < mUsageList.size(); i++) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800476 BatterySipper bs = mUsageList.get(i);
477 bs.computeMobilemspp();
478 if (bs.mobilemspp != 0) {
479 mMobilemsppList.add(bs);
480 }
481 }
Adam Lesinski33dac552015-03-09 15:24:48 -0700482
jackqdyulei1424c1d2017-06-05 16:15:54 -0700483 for (int i = 0; i < mUserSippers.size(); i++) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800484 List<BatterySipper> user = mUserSippers.valueAt(i);
jackqdyulei1424c1d2017-06-05 16:15:54 -0700485 for (int j = 0; j < user.size(); j++) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800486 BatterySipper bs = user.get(j);
487 bs.computeMobilemspp();
488 if (bs.mobilemspp != 0) {
489 mMobilemsppList.add(bs);
490 }
491 }
492 }
493 Collections.sort(mMobilemsppList, new Comparator<BatterySipper>() {
494 @Override
495 public int compare(BatterySipper lhs, BatterySipper rhs) {
Adam Lesinskie08af192015-03-25 16:42:59 -0700496 return Double.compare(rhs.mobilemspp, lhs.mobilemspp);
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800497 }
498 });
499
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800500 processMiscUsage();
501
Adam Lesinskie08af192015-03-25 16:42:59 -0700502 Collections.sort(mUsageList);
503
504 // At this point, we've sorted the list so we are guaranteed the max values are at the top.
505 // We have only added real powers so far.
506 if (!mUsageList.isEmpty()) {
507 mMaxRealPower = mMaxPower = mUsageList.get(0).totalPowerMah;
508 final int usageListCount = mUsageList.size();
509 for (int i = 0; i < usageListCount; i++) {
510 mComputedPower += mUsageList.get(i).totalPowerMah;
511 }
512 }
513
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800514 if (DEBUG) {
Dianne Hackborn099bc622014-01-22 13:39:16 -0800515 Log.d(TAG, "Accuracy: total computed=" + makemAh(mComputedPower) + ", min discharge="
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800516 + makemAh(mMinDrainedPower) + ", max discharge=" + makemAh(mMaxDrainedPower));
517 }
Adam Lesinskie08af192015-03-25 16:42:59 -0700518
Dianne Hackborn099bc622014-01-22 13:39:16 -0800519 mTotalPower = mComputedPower;
520 if (mStats.getLowDischargeAmountSinceCharge() > 1) {
521 if (mMinDrainedPower > mComputedPower) {
522 double amount = mMinDrainedPower - mComputedPower;
523 mTotalPower = mMinDrainedPower;
Adam Lesinskie08af192015-03-25 16:42:59 -0700524 BatterySipper bs = new BatterySipper(DrainType.UNACCOUNTED, null, amount);
525
526 // Insert the BatterySipper in its sorted position.
527 int index = Collections.binarySearch(mUsageList, bs);
528 if (index < 0) {
529 index = -(index + 1);
530 }
531 mUsageList.add(index, bs);
532 mMaxPower = Math.max(mMaxPower, amount);
Dianne Hackborn099bc622014-01-22 13:39:16 -0800533 } else if (mMaxDrainedPower < mComputedPower) {
534 double amount = mComputedPower - mMaxDrainedPower;
Adam Lesinskie08af192015-03-25 16:42:59 -0700535
536 // Insert the BatterySipper in its sorted position.
537 BatterySipper bs = new BatterySipper(DrainType.OVERCOUNTED, null, amount);
538 int index = Collections.binarySearch(mUsageList, bs);
539 if (index < 0) {
540 index = -(index + 1);
541 }
542 mUsageList.add(index, bs);
543 mMaxPower = Math.max(mMaxPower, amount);
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800544 }
545 }
jackqdyulei1424c1d2017-06-05 16:15:54 -0700546
547 // Smear it!
548 final double hiddenPowerMah = removeHiddenBatterySippers(mUsageList);
549 final double totalRemainingPower = getTotalPower() - hiddenPowerMah;
550 if (Math.abs(totalRemainingPower) > 1e-3) {
551 for (int i = 0, size = mUsageList.size(); i < size; i++) {
552 final BatterySipper sipper = mUsageList.get(i);
553 if (!sipper.shouldHide) {
554 sipper.proportionalSmearMah = hiddenPowerMah
555 * ((sipper.totalPowerMah + sipper.screenPowerMah)
556 / totalRemainingPower);
557 sipper.sumPower();
558 }
559 }
560 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800561 }
562
Zoltan Szatmary-Banc3b07a02014-07-01 17:11:07 +0100563 private void processAppUsage(SparseArray<UserHandle> asUsers) {
564 final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
Adam Lesinski76a267b2016-04-20 13:04:59 -0700565 mStatsPeriod = mTypeBatteryRealtimeUs;
Adam Lesinski33dac552015-03-09 15:24:48 -0700566
Adam Lesinski43f222f2015-06-30 12:54:41 -0700567 BatterySipper osSipper = null;
Adam Lesinski33dac552015-03-09 15:24:48 -0700568 final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800569 final int NU = uidStats.size();
570 for (int iu = 0; iu < NU; iu++) {
Adam Lesinski33dac552015-03-09 15:24:48 -0700571 final Uid u = uidStats.valueAt(iu);
Adam Lesinskie08af192015-03-25 16:42:59 -0700572 final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
Adam Lesinski33dac552015-03-09 15:24:48 -0700573
Adam Lesinski76a267b2016-04-20 13:04:59 -0700574 mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
575 mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
jackqdyulei1424c1d2017-06-05 16:15:54 -0700576 mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
577 mStatsType);
Adam Lesinski76a267b2016-04-20 13:04:59 -0700578 mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
jackqdyulei1424c1d2017-06-05 16:15:54 -0700579 mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
580 mStatsType);
Adam Lesinski76a267b2016-04-20 13:04:59 -0700581 mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
582 mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
jackqdyulei1424c1d2017-06-05 16:15:54 -0700583 mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
584 mStatsType);
Mike Ma07305c02018-03-02 16:57:31 -0800585 mMediaPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
Adam Lesinski33dac552015-03-09 15:24:48 -0700586
Adam Lesinskie08af192015-03-25 16:42:59 -0700587 final double totalPower = app.sumPower();
588 if (DEBUG && totalPower != 0) {
589 Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(),
590 makemAh(totalPower)));
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800591 }
592
Adam Lesinski33dac552015-03-09 15:24:48 -0700593 // Add the app to the list if it is consuming power.
Adam Lesinskie08af192015-03-25 16:42:59 -0700594 if (totalPower != 0 || u.getUid() == 0) {
595 //
596 // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list.
597 //
598 final int uid = app.getUid();
599 final int userId = UserHandle.getUserId(uid);
600 if (uid == Process.WIFI_UID) {
601 mWifiSippers.add(app);
602 } else if (uid == Process.BLUETOOTH_UID) {
603 mBluetoothSippers.add(app);
604 } else if (!forAllUsers && asUsers.get(userId) == null
605 && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
606 // We are told to just report this user's apps as one large entry.
607 List<BatterySipper> list = mUserSippers.get(userId);
608 if (list == null) {
609 list = new ArrayList<>();
610 mUserSippers.put(userId, list);
611 }
612 list.add(app);
Bart Searse9b9b732015-04-07 06:14:04 +0000613 } else {
Adam Lesinskie08af192015-03-25 16:42:59 -0700614 mUsageList.add(app);
Bart Searse9b9b732015-04-07 06:14:04 +0000615 }
Bart Searse9b9b732015-04-07 06:14:04 +0000616
Adam Lesinskie08af192015-03-25 16:42:59 -0700617 if (uid == 0) {
Adam Lesinski43f222f2015-06-30 12:54:41 -0700618 osSipper = app;
Adam Lesinskie08af192015-03-25 16:42:59 -0700619 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800620 }
621 }
Adam Lesinski43f222f2015-06-30 12:54:41 -0700622
623 if (osSipper != null) {
624 // The device has probably been awake for longer than the screen on
625 // time and application wake lock time would account for. Assign
626 // this remainder to the OS, if possible.
Adam Lesinski76a267b2016-04-20 13:04:59 -0700627 mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtimeUs,
628 mRawUptimeUs, mStatsType);
Adam Lesinski43f222f2015-06-30 12:54:41 -0700629 osSipper.sumPower();
630 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800631 }
632
633 private void addPhoneUsage() {
Adam Lesinski76a267b2016-04-20 13:04:59 -0700634 long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtimeUs, mStatsType) / 1000;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800635 double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
jackqdyulei1424c1d2017-06-05 16:15:54 -0700636 * phoneOnTimeMs / (60 * 60 * 1000);
Dianne Hackborn099bc622014-01-22 13:39:16 -0800637 if (phoneOnPower != 0) {
Adam Lesinskie08af192015-03-25 16:42:59 -0700638 addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
Dianne Hackborn099bc622014-01-22 13:39:16 -0800639 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800640 }
641
Adam Lesinski76a267b2016-04-20 13:04:59 -0700642 /**
643 * Screen power is the additional power the screen takes while the device is running.
644 */
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800645 private void addScreenUsage() {
646 double power = 0;
Adam Lesinski76a267b2016-04-20 13:04:59 -0700647 long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtimeUs, mStatsType) / 1000;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800648 power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
649 final double screenFullPower =
650 mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
651 for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
652 double screenBinPower = screenFullPower * (i + 0.5f)
653 / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
Adam Lesinski76a267b2016-04-20 13:04:59 -0700654 long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtimeUs, mStatsType)
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800655 / 1000;
jackqdyulei1424c1d2017-06-05 16:15:54 -0700656 double p = screenBinPower * brightnessTime;
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800657 if (DEBUG && p != 0) {
658 Log.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime
Dianne Hackborn099bc622014-01-22 13:39:16 -0800659 + " power=" + makemAh(p / (60 * 60 * 1000)));
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800660 }
661 power += p;
662 }
jackqdyulei1424c1d2017-06-05 16:15:54 -0700663 power /= (60 * 60 * 1000); // To hours
Dianne Hackborn099bc622014-01-22 13:39:16 -0800664 if (power != 0) {
665 addEntry(BatterySipper.DrainType.SCREEN, screenOnTimeMs, power);
666 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800667 }
668
Mike Maeb0d8a72018-02-27 16:41:54 -0800669 /**
670 * Ambient display power is the additional power the screen takes while in ambient display/
671 * screen doze/ always-on display (interchangeable terms) mode. Ambient display power should
672 * be hidden {@link #shouldHideSipper(BatterySipper)}, but should not be included in smearing
673 * {@link #removeHiddenBatterySippers(List)}.
674 */
675 private void addAmbientDisplayUsage() {
Mike Mae074da12018-04-05 17:25:51 -0700676 long ambientDisplayMs = mStats.getScreenDozeTime(mRawRealtimeUs, mStatsType) / 1000;
Mike Maeb0d8a72018-02-27 16:41:54 -0800677 double power = mPowerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)
678 * ambientDisplayMs / (60 * 60 * 1000);
679 if (power > 0) {
680 addEntry(DrainType.AMBIENT_DISPLAY, ambientDisplayMs, power);
681 }
682 }
683
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800684 private void addRadioUsage() {
Adam Lesinskie08af192015-03-25 16:42:59 -0700685 BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
Adam Lesinski76a267b2016-04-20 13:04:59 -0700686 mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtimeUs, mRawUptimeUs,
Adam Lesinskie08af192015-03-25 16:42:59 -0700687 mStatsType);
688 radio.sumPower();
689 if (radio.totalPowerMah > 0) {
690 mUsageList.add(radio);
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800691 }
692 }
693
694 private void aggregateSippers(BatterySipper bs, List<BatterySipper> from, String tag) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700695 for (int i = 0; i < from.size(); i++) {
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800696 BatterySipper wbs = from.get(i);
Adam Lesinskie08af192015-03-25 16:42:59 -0700697 if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTimeMs);
Adam Lesinski33dac552015-03-09 15:24:48 -0700698 bs.add(wbs);
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800699 }
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800700 bs.computeMobilemspp();
Adam Lesinski57123002015-06-12 16:12:07 -0700701 bs.sumPower();
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800702 }
703
Adam Lesinski76a267b2016-04-20 13:04:59 -0700704 /**
705 * Calculate the baseline power usage for the device when it is in suspend and idle.
Mike Ma3d422c32017-10-25 11:08:57 -0700706 * The device is drawing POWER_CPU_SUSPEND power at its lowest power state.
707 * The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held.
Adam Lesinski76a267b2016-04-20 13:04:59 -0700708 */
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800709 private void addIdleUsage() {
Adam Lesinski76a267b2016-04-20 13:04:59 -0700710 final double suspendPowerMaMs = (mTypeBatteryRealtimeUs / 1000) *
Mike Ma3d422c32017-10-25 11:08:57 -0700711 mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND);
Adam Lesinski76a267b2016-04-20 13:04:59 -0700712 final double idlePowerMaMs = (mTypeBatteryUptimeUs / 1000) *
Mike Ma3d422c32017-10-25 11:08:57 -0700713 mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
Adam Lesinski76a267b2016-04-20 13:04:59 -0700714 final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
715 if (DEBUG && totalPowerMah != 0) {
716 Log.d(TAG, "Suspend: time=" + (mTypeBatteryRealtimeUs / 1000)
717 + " power=" + makemAh(suspendPowerMaMs / (60 * 60 * 1000)));
718 Log.d(TAG, "Idle: time=" + (mTypeBatteryUptimeUs / 1000)
719 + " power=" + makemAh(idlePowerMaMs / (60 * 60 * 1000)));
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800720 }
Adam Lesinski76a267b2016-04-20 13:04:59 -0700721
722 if (totalPowerMah != 0) {
723 addEntry(BatterySipper.DrainType.IDLE, mTypeBatteryRealtimeUs / 1000, totalPowerMah);
Dianne Hackborn099bc622014-01-22 13:39:16 -0800724 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800725 }
726
Adam Lesinski33dac552015-03-09 15:24:48 -0700727 /**
728 * We do per-app blaming of WiFi activity. If energy info is reported from the controller,
729 * then only the WiFi process gets blamed here since we normalize power calculations and
730 * assign all the power drain to apps. If energy info is not reported, we attribute the
731 * difference between total running time of WiFi for all apps and the actual running time
732 * of WiFi to the WiFi subsystem.
733 */
734 private void addWiFiUsage() {
Adam Lesinskie08af192015-03-25 16:42:59 -0700735 BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0);
jackqdyulei1424c1d2017-06-05 16:15:54 -0700736 mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs,
737 mStatsType);
Adam Lesinski57123002015-06-12 16:12:07 -0700738 aggregateSippers(bs, mWifiSippers, "WIFI");
739 if (bs.totalPowerMah > 0) {
Adam Lesinskie08af192015-03-25 16:42:59 -0700740 mUsageList.add(bs);
Adam Lesinski33dac552015-03-09 15:24:48 -0700741 }
742 }
743
744 /**
745 * Bluetooth usage is not attributed to any apps yet, so the entire blame goes to the
746 * Bluetooth Category.
747 */
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800748 private void addBluetoothUsage() {
Adam Lesinskie08af192015-03-25 16:42:59 -0700749 BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
Adam Lesinski76a267b2016-04-20 13:04:59 -0700750 mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs,
Adam Lesinskie08af192015-03-25 16:42:59 -0700751 mStatsType);
Adam Lesinski57123002015-06-12 16:12:07 -0700752 aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
753 if (bs.totalPowerMah > 0) {
Adam Lesinskiee36c282015-05-14 13:57:08 -0700754 mUsageList.add(bs);
Dianne Hackborn099bc622014-01-22 13:39:16 -0800755 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800756 }
757
758 private void addUserUsage() {
Adam Lesinskie08af192015-03-25 16:42:59 -0700759 for (int i = 0; i < mUserSippers.size(); i++) {
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800760 final int userId = mUserSippers.keyAt(i);
Adam Lesinskie08af192015-03-25 16:42:59 -0700761 BatterySipper bs = new BatterySipper(DrainType.USER, null, 0);
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800762 bs.userId = userId;
Adam Lesinskie08af192015-03-25 16:42:59 -0700763 aggregateSippers(bs, mUserSippers.valueAt(i), "User");
Adam Lesinskie08af192015-03-25 16:42:59 -0700764 mUsageList.add(bs);
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800765 }
766 }
767
James Carr2dd7e5e2016-07-20 18:48:39 -0700768 private void addMemoryUsage() {
769 BatterySipper memory = new BatterySipper(DrainType.MEMORY, null, 0);
770 mMemoryPowerCalculator.calculateRemaining(memory, mStats, mRawRealtimeUs, mRawUptimeUs,
771 mStatsType);
772 memory.sumPower();
773 if (memory.totalPowerMah > 0) {
774 mUsageList.add(memory);
775 }
776 }
777
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800778 private void processMiscUsage() {
779 addUserUsage();
780 addPhoneUsage();
781 addScreenUsage();
Mike Maeb0d8a72018-02-27 16:41:54 -0800782 addAmbientDisplayUsage();
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800783 addWiFiUsage();
784 addBluetoothUsage();
James Carr2dd7e5e2016-07-20 18:48:39 -0700785 addMemoryUsage();
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800786 addIdleUsage(); // Not including cellular idle power
787 // Don't compute radio usage if it's a wifi-only device
Dianne Hackbornd953c532014-08-16 18:17:38 -0700788 if (!mWifiOnly) {
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800789 addRadioUsage();
790 }
791 }
792
793 private BatterySipper addEntry(DrainType drainType, long time, double power) {
Adam Lesinskie08af192015-03-25 16:42:59 -0700794 BatterySipper bs = new BatterySipper(drainType, null, 0);
795 bs.usagePowerMah = power;
796 bs.usageTimeMs = time;
797 bs.sumPower();
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800798 mUsageList.add(bs);
799 return bs;
800 }
801
Mathew Inwoodc185f082018-08-20 14:28:54 +0100802 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800803 public List<BatterySipper> getUsageList() {
804 return mUsageList;
805 }
806
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800807 public List<BatterySipper> getMobilemsppList() {
808 return mMobilemsppList;
809 }
810
jackqdyulei1424c1d2017-06-05 16:15:54 -0700811 public long getStatsPeriod() {
812 return mStatsPeriod;
813 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800814
jackqdyulei1424c1d2017-06-05 16:15:54 -0700815 public int getStatsType() {
816 return mStatsType;
817 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800818
Mathew Inwoodc185f082018-08-20 14:28:54 +0100819 @UnsupportedAppUsage
jackqdyulei1424c1d2017-06-05 16:15:54 -0700820 public double getMaxPower() {
821 return mMaxPower;
822 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800823
jackqdyulei1424c1d2017-06-05 16:15:54 -0700824 public double getMaxRealPower() {
825 return mMaxRealPower;
826 }
Dianne Hackbornfee756f2014-07-16 17:31:10 -0700827
Mathew Inwoodc185f082018-08-20 14:28:54 +0100828 @UnsupportedAppUsage
jackqdyulei1424c1d2017-06-05 16:15:54 -0700829 public double getTotalPower() {
830 return mTotalPower;
831 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800832
jackqdyulei1424c1d2017-06-05 16:15:54 -0700833 public double getComputedPower() {
834 return mComputedPower;
835 }
Dianne Hackborn099bc622014-01-22 13:39:16 -0800836
Dianne Hackborna7c837f2014-01-15 16:20:44 -0800837 public double getMinDrainedPower() {
838 return mMinDrainedPower;
839 }
840
841 public double getMaxDrainedPower() {
842 return mMaxDrainedPower;
843 }
844
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -0700845 public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
846 return readFully(stream, stream.available());
847 }
848
849 public static byte[] readFully(FileInputStream stream, int avail) throws java.io.IOException {
850 int pos = 0;
851 byte[] data = new byte[avail];
852 while (true) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700853 int amt = stream.read(data, pos, data.length - pos);
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -0700854 //Log.i("foo", "Read " + amt + " bytes at " + pos
855 // + " of avail " + data.length);
856 if (amt <= 0) {
857 //Log.i("foo", "**** FINISHED READING: pos=" + pos
858 // + " len=" + data.length);
859 return data;
860 }
861 pos += amt;
862 avail = stream.available();
jackqdyulei1424c1d2017-06-05 16:15:54 -0700863 if (avail > data.length - pos) {
864 byte[] newData = new byte[pos + avail];
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -0700865 System.arraycopy(data, 0, newData, 0, pos);
866 data = newData;
867 }
868 }
869 }
870
jackqdyulei1424c1d2017-06-05 16:15:54 -0700871 /**
872 * Mark the {@link BatterySipper} that we should hide and smear the screen usage based on
873 * foreground activity time.
874 *
875 * @param sippers sipper list that need to check and remove
876 * @return the total power of the hidden items of {@link BatterySipper}
877 * for proportional smearing
878 */
879 public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
880 double proportionalSmearPowerMah = 0;
881 BatterySipper screenSipper = null;
882 for (int i = sippers.size() - 1; i >= 0; i--) {
883 final BatterySipper sipper = sippers.get(i);
884 sipper.shouldHide = shouldHideSipper(sipper);
885 if (sipper.shouldHide) {
Mike Maeb0d8a72018-02-27 16:41:54 -0800886 if (sipper.drainType != DrainType.OVERCOUNTED
887 && sipper.drainType != DrainType.SCREEN
888 && sipper.drainType != DrainType.AMBIENT_DISPLAY
889 && sipper.drainType != DrainType.UNACCOUNTED
890 && sipper.drainType != DrainType.BLUETOOTH
891 && sipper.drainType != DrainType.WIFI
892 && sipper.drainType != DrainType.IDLE) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700893 // Don't add it if it is overcounted, unaccounted or screen
894 proportionalSmearPowerMah += sipper.totalPowerMah;
895 }
896 }
897
898 if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
899 screenSipper = sipper;
900 }
901 }
902
903 smearScreenBatterySipper(sippers, screenSipper);
904
905 return proportionalSmearPowerMah;
906 }
907
908 /**
909 * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
910 * time.
911 */
912 public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700913 long totalActivityTimeMs = 0;
914 final SparseLongArray activityTimeArray = new SparseLongArray();
915 for (int i = 0, size = sippers.size(); i < size; i++) {
916 final BatteryStats.Uid uid = sippers.get(i).uidObj;
917 if (uid != null) {
jackqdyuleice0fd252017-07-05 11:23:33 -0700918 final long timeMs = getProcessForegroundTimeMs(uid,
919 BatteryStats.STATS_SINCE_CHARGED);
jackqdyulei1424c1d2017-06-05 16:15:54 -0700920 activityTimeArray.put(uid.getUid(), timeMs);
921 totalActivityTimeMs += timeMs;
922 }
923 }
924
jackqdyuleice0fd252017-07-05 11:23:33 -0700925 if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700926 final double screenPowerMah = screenSipper.totalPowerMah;
927 for (int i = 0, size = sippers.size(); i < size; i++) {
928 final BatterySipper sipper = sippers.get(i);
929 sipper.screenPowerMah = screenPowerMah * activityTimeArray.get(sipper.getUid(), 0)
930 / totalActivityTimeMs;
931 }
932 }
933 }
934
935 /**
936 * Check whether we should hide the battery sipper.
937 */
938 public boolean shouldHideSipper(BatterySipper sipper) {
Mike Maeb0d8a72018-02-27 16:41:54 -0800939 final DrainType drainType = sipper.drainType;
jackqdyulei1424c1d2017-06-05 16:15:54 -0700940
Mike Maeb0d8a72018-02-27 16:41:54 -0800941 return drainType == DrainType.IDLE
942 || drainType == DrainType.CELL
943 || drainType == DrainType.SCREEN
944 || drainType == DrainType.AMBIENT_DISPLAY
945 || drainType == DrainType.UNACCOUNTED
946 || drainType == DrainType.OVERCOUNTED
jackqdyulei1424c1d2017-06-05 16:15:54 -0700947 || isTypeService(sipper)
948 || isTypeSystem(sipper);
949 }
950
951 /**
952 * Check whether {@code sipper} is type service
953 */
954 public boolean isTypeService(BatterySipper sipper) {
955 final String[] packages = mPackageManager.getPackagesForUid(sipper.getUid());
956 if (packages == null) {
957 return false;
958 }
959
960 for (String packageName : packages) {
961 if (ArrayUtils.contains(mServicepackageArray, packageName)) {
962 return true;
963 }
964 }
965
966 return false;
967 }
968
969 /**
970 * Check whether {@code sipper} is type system
971 */
972 public boolean isTypeSystem(BatterySipper sipper) {
973 final int uid = sipper.uidObj == null ? -1 : sipper.getUid();
974 sipper.mPackages = mPackageManager.getPackagesForUid(uid);
975 // Classify all the sippers to type system if the range of uid is 0...FIRST_APPLICATION_UID
976 if (uid >= Process.ROOT_UID && uid < Process.FIRST_APPLICATION_UID) {
977 return true;
978 } else if (sipper.mPackages != null) {
979 for (final String packageName : sipper.mPackages) {
980 if (ArrayUtils.contains(mSystemPackageArray, packageName)) {
981 return true;
982 }
983 }
984 }
985
986 return false;
987 }
988
jackqdyuleice0fd252017-07-05 11:23:33 -0700989 public long convertUsToMs(long timeUs) {
990 return timeUs / 1000;
991 }
992
993 public long convertMsToUs(long timeMs) {
994 return timeMs * 1000;
995 }
996
jackqdyulei1424c1d2017-06-05 16:15:54 -0700997 @VisibleForTesting
jackqdyuleice0fd252017-07-05 11:23:33 -0700998 public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) {
jackqdyulei1424c1d2017-06-05 16:15:54 -0700999 final BatteryStats.Timer timer = uid.getForegroundActivityTimer();
1000 if (timer != null) {
jackqdyuleice0fd252017-07-05 11:23:33 -07001001 return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
jackqdyulei1424c1d2017-06-05 16:15:54 -07001002 }
1003
1004 return 0;
1005 }
1006
1007 @VisibleForTesting
jackqdyuleice0fd252017-07-05 11:23:33 -07001008 public long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) {
1009 final long rawRealTimeUs = convertMsToUs(SystemClock.elapsedRealtime());
1010 final int foregroundTypes[] = {BatteryStats.Uid.PROCESS_STATE_TOP};
1011
1012 long timeUs = 0;
1013 for (int type : foregroundTypes) {
1014 final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, which);
1015 timeUs += localTime;
1016 }
1017
1018 // Return the min value of STATE_TOP time and foreground activity time, since both of these
1019 // time have some errors.
1020 return convertUsToMs(
1021 Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)));
1022 }
1023
1024 @VisibleForTesting
jackqdyulei1424c1d2017-06-05 16:15:54 -07001025 public void setPackageManager(PackageManager packageManager) {
1026 mPackageManager = packageManager;
1027 }
1028
1029 @VisibleForTesting
1030 public void setSystemPackageArray(String[] array) {
1031 mSystemPackageArray = array;
1032 }
1033
1034 @VisibleForTesting
1035 public void setServicePackageArray(String[] array) {
1036 mServicepackageArray = array;
1037 }
1038
Mathew Inwoodc185f082018-08-20 14:28:54 +01001039 @UnsupportedAppUsage
Dianne Hackborna7c837f2014-01-15 16:20:44 -08001040 private void load() {
1041 if (mBatteryInfo == null) {
1042 return;
1043 }
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -07001044 mStats = getStats(mBatteryInfo);
Dianne Hackborn2ffa11e2014-04-21 15:56:18 -07001045 if (mCollectBatteryBroadcast) {
1046 mBatteryBroadcast = mContext.registerReceiver(null,
1047 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
1048 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -08001049 }
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -07001050
1051 private static BatteryStatsImpl getStats(IBatteryStats service) {
1052 try {
1053 ParcelFileDescriptor pfd = service.getStatisticsStream();
1054 if (pfd != null) {
Makoto Onuki9700015b2018-07-27 17:06:30 -07001055 if (false) {
1056 Log.d(TAG, "selinux context: "
1057 + SELinux.getFileContext(pfd.getFileDescriptor()));
1058 }
Nimrod Gileadie9be5da2016-02-29 12:33:13 +00001059 try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -07001060 byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
1061 Parcel parcel = Parcel.obtain();
1062 parcel.unmarshall(data, 0, data.length);
1063 parcel.setDataPosition(0);
1064 BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
1065 .createFromParcel(parcel);
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -07001066 return stats;
1067 } catch (IOException e) {
1068 Log.w(TAG, "Unable to read statistics stream", e);
1069 }
1070 }
1071 } catch (RemoteException e) {
1072 Log.w(TAG, "RemoteException:", e);
1073 }
Dianne Hackbornd7c92892014-08-27 16:44:24 -07001074 return new BatteryStatsImpl();
Dianne Hackborn0068d3dc2014-08-06 19:20:25 -07001075 }
Dianne Hackborna7c837f2014-01-15 16:20:44 -08001076}