From 10051afb9669f2fb63de87dcae625d5e215cfb34 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Tue, 6 Mar 2018 13:19:15 -0800 Subject: [PATCH] Add whitelist for anomaly detection. Even though we can add whitelist in config, we still need to have a on device whitelist to reduce the size of config. Use doze whitelist here because we already used it to detect whether we can restrict the app in battery detail page. Bug: 74241534 Test: RunSettingsRoboTests Change-Id: I35b6f3eba9fbc8ae51bb02cd9d5416e4360c388e --- .../AnomalyDetectionJobService.java | 40 +++++----- .../batterytip/BatteryDatabaseManager.java | 13 ++-- .../AnomalyDetectionJobServiceTest.java | 76 +++++++++++++++++++ 3 files changed, 105 insertions(+), 24 deletions(-) diff --git a/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java b/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java index ff715253ad5..83a79bcee1b 100644 --- a/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java +++ b/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobService.java @@ -41,6 +41,7 @@ import android.util.Log; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.fuelgauge.BatteryUtils; +import com.android.settingslib.fuelgauge.PowerWhitelistBackend; import com.android.settingslib.utils.ThreadUtils; import java.util.List; @@ -81,11 +82,12 @@ public class AnomalyDetectionJobService extends JobService { final BatteryStatsHelper batteryStatsHelper = new BatteryStatsHelper(this, true /* collectBatteryBroadcast */); final UserManager userManager = getSystemService(UserManager.class); + final PowerWhitelistBackend powerWhitelistBackend = PowerWhitelistBackend.getInstance(); for (JobWorkItem item = params.dequeueWork(); item != null; item = params.dequeueWork()) { saveAnomalyToDatabase(batteryStatsHelper, userManager, batteryDatabaseManager, - batteryUtils, policy, contentResolver, + batteryUtils, policy, powerWhitelistBackend, contentResolver, item.getIntent().getExtras()); } jobFinished(params, false /* wantsReschedule */); @@ -102,7 +104,8 @@ public class AnomalyDetectionJobService extends JobService { @VisibleForTesting void saveAnomalyToDatabase(BatteryStatsHelper batteryStatsHelper, UserManager userManager, BatteryDatabaseManager databaseManager, BatteryUtils batteryUtils, - BatteryTipPolicy policy, ContentResolver contentResolver, Bundle bundle) { + BatteryTipPolicy policy, PowerWhitelistBackend powerWhitelistBackend, + ContentResolver contentResolver, Bundle bundle) { // The Example of intentDimsValue is: 35:{1:{1:{1:10013|}|}|} final StatsDimensionsValue intentDimsValue = bundle.getParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE); @@ -119,24 +122,25 @@ public class AnomalyDetectionJobService extends JobService { final boolean smartBatteryOn = Settings.Global.getInt(contentResolver, Settings.Global.APP_STANDBY_ENABLED, ON) == ON; final String packageName = batteryUtils.getPackageName(uid); - - if (anomalyType == StatsManagerConfig.AnomalyType.EXCESSIVE_BG) { - // TODO(b/72385333): check battery percentage draining in batterystats - if (batteryUtils.isLegacyApp(packageName) && batteryUtils.isAppHeavilyUsed( - batteryStatsHelper, userManager, uid, - policy.excessiveBgDrainPercentage)) { - Log.e(TAG, "Excessive detected uid=" + uid); - batteryUtils.setForceAppStandby(uid, packageName, - AppOpsManager.MODE_IGNORED); + if (!powerWhitelistBackend.isSysWhitelisted(packageName)) { + if (anomalyType == StatsManagerConfig.AnomalyType.EXCESSIVE_BG) { + // TODO(b/72385333): check battery percentage draining in batterystats + if (batteryUtils.isLegacyApp(packageName) && batteryUtils.isAppHeavilyUsed( + batteryStatsHelper, userManager, uid, + policy.excessiveBgDrainPercentage)) { + Log.e(TAG, "Excessive detected uid=" + uid); + batteryUtils.setForceAppStandby(uid, packageName, + AppOpsManager.MODE_IGNORED); + databaseManager.insertAnomaly(uid, packageName, anomalyType, + smartBatteryOn + ? AnomalyDatabaseHelper.State.AUTO_HANDLED + : AnomalyDatabaseHelper.State.NEW, + timeMs); + } + } else { databaseManager.insertAnomaly(uid, packageName, anomalyType, - smartBatteryOn - ? AnomalyDatabaseHelper.State.AUTO_HANDLED - : AnomalyDatabaseHelper.State.NEW, - timeMs); + AnomalyDatabaseHelper.State.NEW, timeMs); } - } else { - databaseManager.insertAnomaly(uid, packageName, anomalyType, - AnomalyDatabaseHelper.State.NEW, timeMs); } } catch (NullPointerException | IndexOutOfBoundsException e) { Log.e(TAG, "Parse stats dimensions value error.", e); diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java index d0bddecffad..798c8c692a0 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java @@ -18,10 +18,10 @@ package com.android.settings.fuelgauge.batterytip; import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns .ANOMALY_STATE; -import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns - .PACKAGE_NAME; import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns .ANOMALY_TYPE; +import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns + .PACKAGE_NAME; import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns .TIME_STAMP_MS; import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns.UID; @@ -61,10 +61,11 @@ public class BatteryDatabaseManager { /** * Insert an anomaly log to database. - * @param packageName the package name of the app - * @param type the type of the anomaly - * @param anomalyState the state of the anomaly - * @param timestampMs the time when it is happened + * + * @param packageName the package name of the app + * @param type the type of the anomaly + * @param anomalyState the state of the anomaly + * @param timestampMs the time when it is happened */ public synchronized void insertAnomaly(int uid, String packageName, int type, int anomalyState, long timestampMs) { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java index 77e51b1a8bc..aa3d5a86b90 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AnomalyDetectionJobServiceTest.java @@ -17,17 +17,36 @@ package com.android.settings.fuelgauge.batterytip; import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; +import android.app.StatsManager; import android.app.job.JobInfo; import android.app.job.JobScheduler; +import android.content.Context; import android.content.Intent; +import android.os.Bundle; +import android.os.StatsDimensionsValue; +import android.os.UserManager; +import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.fuelgauge.PowerWhitelistBackend; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.shadows.ShadowJobScheduler; @@ -36,6 +55,37 @@ import java.util.concurrent.TimeUnit; @RunWith(SettingsRobolectricTestRunner.class) public class AnomalyDetectionJobServiceTest { + private static final int UID = 123; + private static final String SYSTEM_PACKAGE = "com.android.system"; + @Mock + private BatteryStatsHelper mBatteryStatsHelper; + @Mock + private UserManager mUserManager; + @Mock + private BatteryDatabaseManager mBatteryDatabaseManager; + @Mock + private BatteryUtils mBatteryUtils; + @Mock + private PowerWhitelistBackend mPowerWhitelistBackend; + @Mock + private StatsDimensionsValue mStatsDimensionsValue; + + private BatteryTipPolicy mPolicy; + private Bundle mBundle; + private AnomalyDetectionJobService mAnomalyDetectionJobService; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + mPolicy = new BatteryTipPolicy(mContext); + mBundle = new Bundle(); + mBundle.putParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, mStatsDimensionsValue); + + mAnomalyDetectionJobService = new AnomalyDetectionJobService(); + } @Test public void testScheduleCleanUp() { @@ -50,4 +100,30 @@ public class AnomalyDetectionJobServiceTest { assertThat(pendingJob.getMaxExecutionDelayMillis()) .isEqualTo(TimeUnit.MINUTES.toMillis(30)); } + + @Test + public void testSaveAnomalyToDatabase_systemWhitelisted_doNotSave() { + doReturn(SYSTEM_PACKAGE).when(mBatteryUtils).getPackageName(anyInt()); + doReturn(true).when(mPowerWhitelistBackend).isSysWhitelisted(SYSTEM_PACKAGE); + + mAnomalyDetectionJobService.saveAnomalyToDatabase(mBatteryStatsHelper, mUserManager, + mBatteryDatabaseManager, mBatteryUtils, mPolicy, mPowerWhitelistBackend, + mContext.getContentResolver(), mBundle); + + verify(mBatteryDatabaseManager, never()).insertAnomaly(anyInt(), anyString(), anyInt(), + anyInt(), anyLong()); + } + + @Test + public void testSaveAnomalyToDatabase_normalApp_save() { + doReturn(SYSTEM_PACKAGE).when(mBatteryUtils).getPackageName(anyInt()); + doReturn(false).when(mPowerWhitelistBackend).isSysWhitelisted(SYSTEM_PACKAGE); + + mAnomalyDetectionJobService.saveAnomalyToDatabase(mBatteryStatsHelper, mUserManager, + mBatteryDatabaseManager, mBatteryUtils, mPolicy, mPowerWhitelistBackend, + mContext.getContentResolver(), mBundle); + + verify(mBatteryDatabaseManager).insertAnomaly(anyInt(), anyString(), anyInt(), anyInt(), + anyLong()); + } }