diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 35a173b6142..dd30e692422 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -39,6 +39,9 @@ public interface PowerUsageFeatureProvider { /** Check whether the battery tips card is enabled in the battery usage page */ boolean isBatteryTipsEnabled(); + /** Check whether to log the optimization mode of app entry in period job */ + boolean isAppOptimizationModeLogged(); + /** * Returns a threshold (in milliseconds) for the minimal screen on time in battery usage list */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index f0616ed7edc..5c66dbc0fa3 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -83,6 +83,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider return false; } + @Override + public boolean isAppOptimizationModeLogged() { + return false; + } + @Override public double getBatteryUsageListScreenOnTimeThresholdInMs() { return 0; diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java new file mode 100644 index 00000000000..6b35fb9cccb --- /dev/null +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 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 android.content.Context; +import android.util.ArrayMap; + +import androidx.annotation.VisibleForTesting; + +import com.android.settings.fuelgauge.BatteryOptimizeUtils; +import com.android.settingslib.fuelgauge.PowerAllowlistBackend; + +import java.util.Map; + +/** A cache to log battery optimization mode of an app */ +final class BatteryOptimizationModeCache { + private static final String TAG = "BatteryOptimizationModeCache"; + + @VisibleForTesting final Map mBatteryOptimizeModeCacheMap; + + private final Context mContext; + + BatteryOptimizationModeCache(final Context context) { + mContext = context; + mBatteryOptimizeModeCacheMap = new ArrayMap<>(); + PowerAllowlistBackend.getInstance(mContext).refreshList(); + } + + BatteryOptimizationMode getBatteryOptimizeMode(final int uid, final String packageName) { + if (!mBatteryOptimizeModeCacheMap.containsKey(uid)) { + final BatteryOptimizeUtils batteryOptimizeUtils = + new BatteryOptimizeUtils(mContext, uid, packageName); + mBatteryOptimizeModeCacheMap.put( + uid, + BatteryOptimizationMode.forNumber( + batteryOptimizeUtils.getAppOptimizationMode(/* refreshList= */ false))); + } + return mBatteryOptimizeModeCacheMap.get(uid); + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java index 870faecd106..26bb6dd0a01 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java @@ -27,6 +27,7 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.PowerUsageFeatureProvider; import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils; import com.android.settings.overlay.FeatureFactory; @@ -124,9 +125,15 @@ public final class BatteryUsageDataLoader { userIdsSeries, /* isFromPeriodJob= */ true, batteryDiffDataMap -> { + final PowerUsageFeatureProvider featureProvider = + FeatureFactory.getFeatureFactory() + .getPowerUsageFeatureProvider(); DatabaseUtils.sendBatteryUsageSlotData( context, - ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap)); + ConvertUtils.convertToBatteryUsageSlotList( + context, + batteryDiffDataMap, + featureProvider.isAppOptimizationModeLogged())); if (batteryDiffDataMap.values().stream() .anyMatch( data -> @@ -135,12 +142,10 @@ public final class BatteryUsageDataLoader { .isEmpty() || !data.getAppDiffEntryList() .isEmpty()))) { - FeatureFactory.getFeatureFactory() - .getPowerUsageFeatureProvider() - .detectPowerAnomaly( - context, - /* displayDrain= */ 0, - DetectRequestSourceType.TYPE_DATA_LOADER); + featureProvider.detectPowerAnomaly( + context, + /* displayDrain= */ 0, + DetectRequestSourceType.TYPE_DATA_LOADER); } }); if (batteryLevelData == null) { diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java index df9f0634e04..1cbe6dae4cc 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java @@ -345,10 +345,15 @@ public final class ConvertUtils { /** Converts from {@link Map} to {@link List} */ public static List convertToBatteryUsageSlotList( - final Map batteryDiffDataMap) { + final Context context, + final Map batteryDiffDataMap, + final boolean isAppOptimizationModeLogged) { List batteryUsageSlotList = new ArrayList<>(); + final BatteryOptimizationModeCache optimizationModeCache = + isAppOptimizationModeLogged ? new BatteryOptimizationModeCache(context) : null; for (BatteryDiffData batteryDiffData : batteryDiffDataMap.values()) { - batteryUsageSlotList.add(convertToBatteryUsageSlot(batteryDiffData)); + batteryUsageSlotList.add( + convertToBatteryUsageSlot(batteryDiffData, optimizationModeCache)); } return batteryUsageSlotList; } @@ -479,9 +484,10 @@ public final class ConvertUtils { } } - @VisibleForTesting - static BatteryUsageDiff convertToBatteryUsageDiff(BatteryDiffEntry batteryDiffEntry) { + static BatteryUsageDiff convertToBatteryUsageDiff( + final BatteryDiffEntry batteryDiffEntry, + final @Nullable BatteryOptimizationModeCache optimizationModeCache) { BatteryUsageDiff.Builder builder = BatteryUsageDiff.newBuilder() .setUid(batteryDiffEntry.mUid) @@ -511,11 +517,18 @@ public final class ConvertUtils { if (batteryDiffEntry.mLegacyLabel != null) { builder.setLabel(batteryDiffEntry.mLegacyLabel); } + // Log the battery optimization mode of AppEntry while converting to batteryUsageSlot. + if (optimizationModeCache != null && !batteryDiffEntry.isSystemEntry()) { + builder.setAppOptimizationMode( + optimizationModeCache.getBatteryOptimizeMode( + (int) batteryDiffEntry.mUid, batteryDiffEntry.getPackageName())); + } return builder.build(); } private static BatteryUsageSlot convertToBatteryUsageSlot( - final BatteryDiffData batteryDiffData) { + final BatteryDiffData batteryDiffData, + final @Nullable BatteryOptimizationModeCache optimizationModeCache) { if (batteryDiffData == null) { return BatteryUsageSlot.getDefaultInstance(); } @@ -527,10 +540,11 @@ public final class ConvertUtils { .setEndBatteryLevel(batteryDiffData.getEndBatteryLevel()) .setScreenOnTime(batteryDiffData.getScreenOnTime()); for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getAppDiffEntryList()) { - builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry)); + builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry, optimizationModeCache)); } for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getSystemDiffEntryList()) { - builder.addSystemUsage(convertToBatteryUsageDiff(batteryDiffEntry)); + builder.addSystemUsage( + convertToBatteryUsageDiff(batteryDiffEntry, /* optimizationModeCache= */ null)); } return builder.build(); } diff --git a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto index 7f677707ded..4e3e3c4d6cd 100644 --- a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto +++ b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto @@ -14,6 +14,13 @@ message BatteryUsageSlot { repeated BatteryUsageDiff system_usage = 7; } +enum BatteryOptimizationMode { + MODE_UNKNOWN = 0; + MODE_RESTRICTED = 1; + MODE_UNRESTRICTED = 2; + MODE_OPTIMIZED = 3; +} + message BatteryUsageDiff { optional int64 uid = 1; optional int64 user_id = 2; @@ -32,4 +39,5 @@ message BatteryUsageDiff { optional int64 background_usage_time = 15; optional int64 screen_on_time = 16; optional int64 foreground_service_usage_time = 17; + optional BatteryOptimizationMode app_optimization_mode = 18; } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java index db4c359a9ff..3158688a884 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java @@ -72,6 +72,11 @@ public class PowerUsageFeatureProviderImplTest { assertThat(mPowerFeatureProvider.isBatteryTipsEnabled()).isFalse(); } + @Test + public void testIsAppOptimizationModeLogged_returnFalse() { + assertThat(mPowerFeatureProvider.isAppOptimizationModeLogged()).isFalse(); + } + @Test public void testGetBatteryUsageListConsumePowerThreshold_return0() { assertThat(mPowerFeatureProvider.getBatteryUsageListConsumePowerThreshold()).isEqualTo(0.0); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java index 5ce449b5d1d..3ed2dd1aa89 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java @@ -382,9 +382,13 @@ public final class ConvertUtilsTest { /* foregroundServiceUsageConsumePower= */ 1.3, /* backgroundUsageConsumePower= */ 1.4, /* cachedUsageConsumePower= */ 1.5); + BatteryOptimizationModeCache optimizationModeCache = + new BatteryOptimizationModeCache(mContext); + optimizationModeCache.mBatteryOptimizeModeCacheMap.put( + (int) batteryDiffEntry.mUid, BatteryOptimizationMode.MODE_OPTIMIZED); final BatteryUsageDiff batteryUsageDiff = - ConvertUtils.convertToBatteryUsageDiff(batteryDiffEntry); + ConvertUtils.convertToBatteryUsageDiff(batteryDiffEntry, optimizationModeCache); assertThat(batteryUsageDiff.getUid()).isEqualTo(101L); assertThat(batteryUsageDiff.getUserId()).isEqualTo(1001L); @@ -402,6 +406,8 @@ public final class ConvertUtilsTest { assertThat(batteryUsageDiff.getBackgroundUsageTime()).isEqualTo(5678L); assertThat(batteryUsageDiff.getScreenOnTime()).isEqualTo(123L); assertThat(batteryUsageDiff.getKey()).isEqualTo("key"); + assertThat(batteryUsageDiff.getAppOptimizationMode()) + .isEqualTo(BatteryOptimizationMode.MODE_OPTIMIZED); assertThat(batteryUsageDiff.hasPackageName()).isFalse(); assertThat(batteryUsageDiff.hasLabel()).isFalse(); } @@ -591,7 +597,7 @@ public final class ConvertUtilsTest { Map.of(11L, batteryDiffData1, 21L, batteryDiffData2, 31L, batteryDiffData3); final List batteryUsageSlotList = - ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap); + ConvertUtils.convertToBatteryUsageSlotList(mContext, batteryDiffDataMap, false); assertThat(batteryUsageSlotList).hasSize(3); assertThat(batteryUsageSlotList.stream().map((s) -> s.getScreenOnTime()).sorted().toList())