Files
packages_apps_Settings/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
mxyyiyi c3b20d3a31 Also clear the foreground service usage time for BatteryDiffEntry should hide background usage time.
- Usage time in background is the sum{bg + fgs} usage time

Bug: 371919020
Fix: 371919020
Test: atest DataProcessorTest
Flag: EXEMPT for simple fix
Change-Id: I058d8511eac7510e2df6d9ac1713824cd8dbf3ba
2024-10-09 13:31:18 +08:00

345 lines
14 KiB
Java

/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batteryusage;
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTimeForLogging;
import android.content.Context;
import android.os.BatteryConsumer;
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/** Wraps the battery usage diff data for each entry used for battery usage app list. */
public class BatteryDiffData {
static final double SMALL_PERCENTAGE_THRESHOLD = 1f;
private final long mStartTimestamp;
private final long mEndTimestamp;
private final int mStartBatteryLevel;
private final int mEndBatteryLevel;
private final long mScreenOnTime;
private final List<BatteryDiffEntry> mAppEntries;
private final List<BatteryDiffEntry> mSystemEntries;
/** Constructor for the diff entries. */
public BatteryDiffData(
final Context context,
final long startTimestamp,
final long endTimestamp,
final int startBatteryLevel,
final int endBatteryLevel,
final long screenOnTime,
final @NonNull List<BatteryDiffEntry> appDiffEntries,
final @NonNull List<BatteryDiffEntry> systemDiffEntries,
final @NonNull Set<String> systemAppsPackageNames,
final @NonNull Set<Integer> systemAppsUids,
final boolean isAccumulated) {
mStartTimestamp = startTimestamp;
mEndTimestamp = endTimestamp;
mStartBatteryLevel = startBatteryLevel;
mEndBatteryLevel = endBatteryLevel;
mScreenOnTime = screenOnTime;
mAppEntries = appDiffEntries;
mSystemEntries = systemDiffEntries;
if (!isAccumulated) {
final PowerUsageFeatureProvider featureProvider =
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
purgeBatteryDiffData(featureProvider);
combineBatteryDiffEntry(
context, featureProvider, systemAppsPackageNames, systemAppsUids);
}
processAndSortEntries(mAppEntries);
processAndSortEntries(mSystemEntries);
}
/** Gets the start timestamp. */
public long getStartTimestamp() {
return mStartTimestamp;
}
/** Gets the end timestamp. */
public long getEndTimestamp() {
return mEndTimestamp;
}
int getStartBatteryLevel() {
return mStartBatteryLevel;
}
int getEndBatteryLevel() {
return mEndBatteryLevel;
}
long getScreenOnTime() {
return mScreenOnTime;
}
/** Gets the {@link BatteryDiffEntry} list for apps. */
public List<BatteryDiffEntry> getAppDiffEntryList() {
return mAppEntries;
}
List<BatteryDiffEntry> getSystemDiffEntryList() {
return mSystemEntries;
}
@Override
public String toString() {
return new StringBuilder("BatteryDiffData{")
.append("startTimestamp:" + utcToLocalTimeForLogging(mStartTimestamp))
.append("|endTimestamp:" + utcToLocalTimeForLogging(mEndTimestamp))
.append("|startLevel:" + mStartBatteryLevel)
.append("|endLevel:" + mEndBatteryLevel)
.append("|screenOnTime:" + mScreenOnTime)
.append("|appEntries.size:" + mAppEntries.size())
.append("|systemEntries.size:" + mSystemEntries.size())
.append("}")
.toString();
}
/** Removes fake usage data and hidden packages. */
private void purgeBatteryDiffData(final PowerUsageFeatureProvider featureProvider) {
purgeBatteryDiffData(featureProvider, mAppEntries);
purgeBatteryDiffData(featureProvider, mSystemEntries);
}
/** Combines into SystemAppsBatteryDiffEntry and OthersBatteryDiffEntry. */
private void combineBatteryDiffEntry(
final Context context,
final PowerUsageFeatureProvider featureProvider,
final @NonNull Set<String> systemAppsPackageNames,
final @NonNull Set<Integer> systemAppsUids) {
combineIntoUninstalledApps(context, mAppEntries);
combineIntoSystemApps(
context, featureProvider, systemAppsPackageNames, systemAppsUids, mAppEntries);
combineSystemItemsIntoOthers(context, featureProvider, mSystemEntries);
}
private static void purgeBatteryDiffData(
final PowerUsageFeatureProvider featureProvider, final List<BatteryDiffEntry> entries) {
final double screenOnTimeThresholdInMs =
featureProvider.getBatteryUsageListScreenOnTimeThresholdInMs();
final double consumePowerThreshold =
featureProvider.getBatteryUsageListConsumePowerThreshold();
final Set<Integer> hideSystemComponentSet = featureProvider.getHideSystemComponentSet();
final Set<String> hideBackgroundUsageTimeSet =
featureProvider.getHideBackgroundUsageTimeSet();
final Set<String> hideApplicationSet = featureProvider.getHideApplicationSet();
final Iterator<BatteryDiffEntry> iterator = entries.iterator();
while (iterator.hasNext()) {
final BatteryDiffEntry entry = iterator.next();
final long screenOnTimeInMs =
entry.isSystemEntry()
? entry.mForegroundUsageTimeInMs
: entry.mScreenOnTimeInMs;
final double comsumePower = entry.mConsumePower;
final String packageName = entry.getPackageName();
final Integer componentId = entry.mComponentId;
if ((screenOnTimeInMs < screenOnTimeThresholdInMs
&& comsumePower < consumePowerThreshold)
|| ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
|| hideSystemComponentSet.contains(componentId)
|| (packageName != null && hideApplicationSet.contains(packageName))) {
iterator.remove();
}
if (packageName != null && hideBackgroundUsageTimeSet.contains(packageName)) {
entry.mBackgroundUsageTimeInMs = 0;
entry.mForegroundServiceUsageTimeInMs = 0;
}
}
}
private static void combineIntoSystemApps(
final Context context,
final PowerUsageFeatureProvider featureProvider,
final @NonNull Set<String> systemAppsPackageNames,
final @NonNull Set<Integer> systemAppsUids,
final @NonNull List<BatteryDiffEntry> appEntries) {
final List<String> systemAppsAllowlist = featureProvider.getSystemAppsAllowlist();
BatteryDiffEntry systemAppsDiffEntry = null;
final Iterator<BatteryDiffEntry> appListIterator = appEntries.iterator();
while (appListIterator.hasNext()) {
final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
if (needsCombineInSystemApp(
batteryDiffEntry,
systemAppsAllowlist,
systemAppsPackageNames,
systemAppsUids)) {
if (systemAppsDiffEntry == null) {
systemAppsDiffEntry =
new BatteryDiffEntry(
context,
BatteryDiffEntry.SYSTEM_APPS_KEY,
BatteryDiffEntry.SYSTEM_APPS_KEY,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
}
systemAppsDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
systemAppsDiffEntry.mForegroundUsageTimeInMs +=
batteryDiffEntry.mForegroundUsageTimeInMs;
systemAppsDiffEntry.setTotalConsumePower(batteryDiffEntry.getTotalConsumePower());
appListIterator.remove();
}
}
if (systemAppsDiffEntry != null) {
appEntries.add(systemAppsDiffEntry);
}
}
private static void combineIntoUninstalledApps(
final Context context, final @NonNull List<BatteryDiffEntry> appEntries) {
BatteryDiffEntry uninstalledAppDiffEntry = null;
final Iterator<BatteryDiffEntry> appListIterator = appEntries.iterator();
while (appListIterator.hasNext()) {
final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
if (!batteryDiffEntry.isUninstalledEntry()) {
continue;
}
if (uninstalledAppDiffEntry == null) {
uninstalledAppDiffEntry =
new BatteryDiffEntry(
context,
BatteryDiffEntry.UNINSTALLED_APPS_KEY,
BatteryDiffEntry.UNINSTALLED_APPS_KEY,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
}
uninstalledAppDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
uninstalledAppDiffEntry.mForegroundUsageTimeInMs +=
batteryDiffEntry.mForegroundUsageTimeInMs;
uninstalledAppDiffEntry.setTotalConsumePower(batteryDiffEntry.getTotalConsumePower());
appListIterator.remove();
}
if (uninstalledAppDiffEntry != null) {
appEntries.add(uninstalledAppDiffEntry);
}
}
private static void combineSystemItemsIntoOthers(
final Context context,
final PowerUsageFeatureProvider featureProvider,
final List<BatteryDiffEntry> systemEntries) {
final Set<Integer> othersSystemComponentSet = featureProvider.getOthersSystemComponentSet();
final Set<String> othersCustomComponentNameSet =
featureProvider.getOthersCustomComponentNameSet();
BatteryDiffEntry othersDiffEntry = null;
final Iterator<BatteryDiffEntry> systemListIterator = systemEntries.iterator();
while (systemListIterator.hasNext()) {
final BatteryDiffEntry batteryDiffEntry = systemListIterator.next();
final int componentId = batteryDiffEntry.mComponentId;
if (othersSystemComponentSet.contains(componentId)
|| (componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
&& othersCustomComponentNameSet.contains(
batteryDiffEntry.getAppLabel()))) {
if (othersDiffEntry == null) {
othersDiffEntry =
new BatteryDiffEntry(
context,
BatteryDiffEntry.OTHERS_KEY,
BatteryDiffEntry.OTHERS_KEY,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
}
othersDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
othersDiffEntry.setTotalConsumePower(batteryDiffEntry.getTotalConsumePower());
systemListIterator.remove();
}
}
if (othersDiffEntry != null) {
systemEntries.add(othersDiffEntry);
}
}
@VisibleForTesting
static boolean needsCombineInSystemApp(
final BatteryDiffEntry batteryDiffEntry,
final @NonNull List<String> systemAppsAllowlist,
final @NonNull Set<String> systemAppsPackageNames,
final @NonNull Set<Integer> systemAppsUids) {
if (batteryDiffEntry.mIsHidden) {
return true;
}
final String packageName = batteryDiffEntry.getPackageName();
if (packageName == null || packageName.isEmpty()) {
return false;
}
if (systemAppsAllowlist.contains(packageName)) {
return true;
}
int uid = (int) batteryDiffEntry.mUid;
return systemAppsPackageNames.contains(packageName) || systemAppsUids.contains(uid);
}
/**
* Sets total consume power, and adjusts the percentages to ensure the total round percentage
* could be 100%, and then sorts entries based on the sorting key.
*/
public static void processAndSortEntries(final List<BatteryDiffEntry> batteryDiffEntries) {
if (batteryDiffEntries.isEmpty()) {
return;
}
// Sets total consume power.
double totalConsumePower = 0.0;
for (BatteryDiffEntry batteryDiffEntry : batteryDiffEntries) {
totalConsumePower += batteryDiffEntry.mConsumePower;
}
for (BatteryDiffEntry batteryDiffEntry : batteryDiffEntries) {
batteryDiffEntry.setTotalConsumePower(totalConsumePower);
}
// Adjusts percentages to show.
// The lower bound is treating all the small percentages as 0.
// The upper bound is treating all the small percentages as 1.
int totalLowerBound = 0;
int totalUpperBound = 0;
for (BatteryDiffEntry entry : batteryDiffEntries) {
if (entry.getPercentage() < SMALL_PERCENTAGE_THRESHOLD) {
totalUpperBound += 1;
} else {
int roundPercentage = Math.round((float) entry.getPercentage());
totalLowerBound += roundPercentage;
totalUpperBound += roundPercentage;
}
}
if (totalLowerBound > 100 || totalUpperBound < 100) {
Collections.sort(batteryDiffEntries, BatteryDiffEntry.COMPARATOR);
for (int i = 0; i < totalLowerBound - 100 && i < batteryDiffEntries.size(); i++) {
batteryDiffEntries.get(i).setAdjustPercentageOffset(-1);
}
for (int i = 0; i < 100 - totalUpperBound && i < batteryDiffEntries.size(); i++) {
batteryDiffEntries.get(i).setAdjustPercentageOffset(1);
}
}
// Sorts entries.
Collections.sort(batteryDiffEntries, BatteryDiffEntry.COMPARATOR);
}
}