Clean up BatteryAppListPreferenceController
Bug: 256123455 Bug: 258576047 Fix: 258576047 Test: presubmit Change-Id: I8c3d05f76e7a6995fccc34b2cc60ee126bb3d350
This commit is contained in:
@@ -21,22 +21,29 @@ import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLoca
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.BatteryConsumer;
|
||||
import android.os.BatteryStatsManager;
|
||||
import android.os.BatteryUsageStats;
|
||||
import android.os.BatteryUsageStatsQuery;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.os.PowerProfile;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
@@ -48,6 +55,7 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -62,12 +70,14 @@ import java.util.stream.Collectors;
|
||||
public final class DataProcessor {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "DataProcessor";
|
||||
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
||||
private static final int MIN_DAILY_DATA_SIZE = 2;
|
||||
private static final int MIN_TIMESTAMP_DATA_SIZE = 2;
|
||||
private static final int MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP = 5;
|
||||
// Maximum total time value for each hourly slot cumulative data at most 2 hours.
|
||||
private static final float TOTAL_HOURLY_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2;
|
||||
private static final long MIN_TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
|
||||
private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
|
||||
private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new HashMap<>();
|
||||
private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY =
|
||||
new BatteryHistEntry(new ContentValues());
|
||||
@@ -188,24 +198,26 @@ public final class DataProcessor {
|
||||
@Nullable
|
||||
public static List<BatteryEntry> generateBatteryEntryListFromBatteryUsageStats(
|
||||
final Context context,
|
||||
@Nullable final BatteryUsageStats batteryUsageStats,
|
||||
@Nullable BatteryAppListPreferenceController batteryAppListPreferenceController) {
|
||||
@Nullable final BatteryUsageStats batteryUsageStats) {
|
||||
if (batteryUsageStats == null) {
|
||||
Log.w(TAG, "batteryUsageStats is null content");
|
||||
return null;
|
||||
}
|
||||
// Loads the battery consuming data.
|
||||
final BatteryAppListPreferenceController controller =
|
||||
batteryAppListPreferenceController == null
|
||||
? new BatteryAppListPreferenceController(
|
||||
context,
|
||||
/*preferenceKey=*/ null,
|
||||
/*lifecycle=*/ null,
|
||||
/*activity*=*/ null,
|
||||
/*fragment=*/ null)
|
||||
: batteryAppListPreferenceController;
|
||||
|
||||
return controller.getBatteryEntryList(batteryUsageStats, /*showAllApps=*/ true);
|
||||
if (!shouldShowBatteryAttributionList(context)) {
|
||||
return null;
|
||||
}
|
||||
final BatteryUtils batteryUtils = BatteryUtils.getInstance(context);
|
||||
final int dischargePercentage = Math.max(0, batteryUsageStats.getDischargePercentage());
|
||||
final List<BatteryEntry> usageList = getCoalescedUsageList(
|
||||
context, batteryUtils, batteryUsageStats, /*loadDataInBackground=*/ false);
|
||||
final double totalPower = batteryUsageStats.getConsumedPower();
|
||||
for (int i = 0; i < usageList.size(); i++) {
|
||||
final BatteryEntry entry = usageList.get(i);
|
||||
final double percentOfTotal = batteryUtils.calculateBatteryPercent(
|
||||
entry.getConsumedPower(), totalPower, dischargePercentage);
|
||||
entry.mPercent = percentOfTotal;
|
||||
}
|
||||
return usageList;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,10 +546,7 @@ public final class DataProcessor {
|
||||
try {
|
||||
final BatteryUsageStats batteryUsageStats = getBatteryUsageStats(context);
|
||||
final List<BatteryEntry> batteryEntryList =
|
||||
generateBatteryEntryListFromBatteryUsageStats(
|
||||
context,
|
||||
batteryUsageStats,
|
||||
/*batteryAppListPreferenceController=*/ null);
|
||||
generateBatteryEntryListFromBatteryUsageStats(context, batteryUsageStats);
|
||||
batteryDiffData = generateBatteryDiffData(context, batteryEntryList, batteryUsageStats);
|
||||
closeBatteryUsageStats(batteryUsageStats);
|
||||
} catch (RuntimeException e) {
|
||||
@@ -1100,6 +1109,136 @@ public final class DataProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldShowBatteryAttributionList(final Context context) {
|
||||
final PowerProfile powerProfile = new PowerProfile(context);
|
||||
// Cheap hack to try to figure out if the power_profile.xml was populated.
|
||||
final double averagePowerForOrdinal = powerProfile.getAveragePowerForOrdinal(
|
||||
PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL, 0);
|
||||
final boolean shouldShowBatteryAttributionList =
|
||||
averagePowerForOrdinal >= MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP;
|
||||
if (!shouldShowBatteryAttributionList) {
|
||||
Log.w(TAG, "shouldShowBatteryAttributionList(): " + averagePowerForOrdinal);
|
||||
}
|
||||
return shouldShowBatteryAttributionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to coalesce some UIDs. For example, dex2oat runs under a shared gid that
|
||||
* exists for all users of the same app. We detect this case and merge the power use
|
||||
* for dex2oat to the device OWNER's use of the app.
|
||||
*
|
||||
* @return A sorted list of apps using power.
|
||||
*/
|
||||
private static List<BatteryEntry> getCoalescedUsageList(final Context context,
|
||||
final BatteryUtils batteryUtils,
|
||||
final BatteryUsageStats batteryUsageStats,
|
||||
final boolean loadDataInBackground) {
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
final UserManager userManager = context.getSystemService(UserManager.class);
|
||||
final SparseArray<BatteryEntry> batteryEntryList = new SparseArray<>();
|
||||
final ArrayList<BatteryEntry> results = new ArrayList<>();
|
||||
final List<UidBatteryConsumer> uidBatteryConsumers =
|
||||
batteryUsageStats.getUidBatteryConsumers();
|
||||
|
||||
// Sort to have all apps with "real" UIDs first, followed by apps that are supposed
|
||||
// to be combined with the real ones.
|
||||
uidBatteryConsumers.sort(Comparator.comparingInt(
|
||||
consumer -> consumer.getUid() == getRealUid(consumer) ? 0 : 1));
|
||||
|
||||
for (int i = 0, size = uidBatteryConsumers.size(); i < size; i++) {
|
||||
final UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
|
||||
final int uid = getRealUid(consumer);
|
||||
|
||||
final String[] packages = packageManager.getPackagesForUid(uid);
|
||||
if (batteryUtils.shouldHideUidBatteryConsumerUnconditionally(consumer, packages)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final boolean isHidden = batteryUtils.shouldHideUidBatteryConsumer(consumer, packages);
|
||||
final int index = batteryEntryList.indexOfKey(uid);
|
||||
if (index < 0) {
|
||||
// New entry.
|
||||
batteryEntryList.put(uid, new BatteryEntry(context, userManager, consumer,
|
||||
isHidden, uid, packages, null, loadDataInBackground));
|
||||
} else {
|
||||
// Combine BatterySippers if we already have one with this UID.
|
||||
final BatteryEntry existingSipper = batteryEntryList.valueAt(index);
|
||||
existingSipper.add(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
final BatteryConsumer deviceConsumer = batteryUsageStats.getAggregateBatteryConsumer(
|
||||
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
|
||||
final BatteryConsumer appsConsumer = batteryUsageStats.getAggregateBatteryConsumer(
|
||||
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
|
||||
|
||||
for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
|
||||
componentId++) {
|
||||
results.add(new BatteryEntry(context, componentId,
|
||||
deviceConsumer.getConsumedPower(componentId),
|
||||
appsConsumer.getConsumedPower(componentId),
|
||||
deviceConsumer.getUsageDurationMillis(componentId)));
|
||||
}
|
||||
|
||||
for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
|
||||
componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||
+ deviceConsumer.getCustomPowerComponentCount();
|
||||
componentId++) {
|
||||
results.add(new BatteryEntry(context, componentId,
|
||||
deviceConsumer.getCustomPowerComponentName(componentId),
|
||||
deviceConsumer.getConsumedPowerForCustomComponent(componentId),
|
||||
appsConsumer.getConsumedPowerForCustomComponent(componentId)));
|
||||
}
|
||||
|
||||
final List<UserBatteryConsumer> userBatteryConsumers =
|
||||
batteryUsageStats.getUserBatteryConsumers();
|
||||
for (int i = 0, size = userBatteryConsumers.size(); i < size; i++) {
|
||||
final UserBatteryConsumer consumer = userBatteryConsumers.get(i);
|
||||
results.add(new BatteryEntry(context, userManager, consumer, /* isHidden */ true,
|
||||
Process.INVALID_UID, null, null, loadDataInBackground));
|
||||
}
|
||||
|
||||
final int numUidSippers = batteryEntryList.size();
|
||||
|
||||
for (int i = 0; i < numUidSippers; i++) {
|
||||
results.add(batteryEntryList.valueAt(i));
|
||||
}
|
||||
|
||||
// The sort order must have changed, so re-sort based on total power use.
|
||||
results.sort(BatteryEntry.COMPARATOR);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static int getRealUid(final UidBatteryConsumer consumer) {
|
||||
int realUid = consumer.getUid();
|
||||
|
||||
// Check if this UID is a shared GID. If so, we combine it with the OWNER's
|
||||
// actual app UID.
|
||||
if (isSharedGid(consumer.getUid())) {
|
||||
realUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
|
||||
UserHandle.getAppIdFromSharedAppGid(consumer.getUid()));
|
||||
}
|
||||
|
||||
// Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
|
||||
if (isSystemUid(realUid)
|
||||
&& !MEDIASERVER_PACKAGE_NAME.equals(consumer.getPackageWithHighestDrain())) {
|
||||
// Use the system UID for all UIDs running in their own sandbox that
|
||||
// are not apps. We exclude mediaserver because we already are expected to
|
||||
// report that as a separate item.
|
||||
realUid = Process.SYSTEM_UID;
|
||||
}
|
||||
return realUid;
|
||||
}
|
||||
|
||||
private static boolean isSharedGid(final int uid) {
|
||||
return UserHandle.getAppIdFromSharedAppGid(uid) > 0;
|
||||
}
|
||||
|
||||
private static boolean isSystemUid(final int uid) {
|
||||
final int appUid = UserHandle.getAppId(uid);
|
||||
return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID;
|
||||
}
|
||||
|
||||
private static boolean isUsageMapValid(
|
||||
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap,
|
||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay) {
|
||||
|
Reference in New Issue
Block a user