Loading AndroidManifest.xml +0 −14 Original line number Diff line number Diff line Loading @@ -4692,20 +4692,6 @@ android:permission="android.permission.MANAGE_SLICE_PERMISSIONS" android:exported="true" /> <!-- Couldn't be triggered from outside of settings. Statsd can trigger it because we send PendingIntent to it--> <receiver android:name=".fuelgauge.batterytip.AnomalyDetectionReceiver" android:exported="false" /> <service android:name=".fuelgauge.batterytip.AnomalyCleanupJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> <service android:name=".fuelgauge.batterytip.AnomalyConfigJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> <service android:name=".fuelgauge.batterytip.AnomalyDetectionJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> <provider android:name=".homepage.contextualcards.CardContentProvider" android:authorities="${applicationId}.homepage.CardContentProvider" Loading src/com/android/settings/SettingsDumpService.java +0 −16 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import androidx.annotation.VisibleForTesting; import com.android.settings.applications.ProcStatsData; import com.android.settings.datausage.lib.DataUsageLib; import com.android.settings.fuelgauge.batterytip.AnomalyConfigJobService; import com.android.settings.network.MobileNetworkRepository; import com.android.settingslib.net.DataUsageController; Loading Loading @@ -99,7 +98,6 @@ public class SettingsDumpService extends Service { dump.put(KEY_DATAUSAGE, dumpDataUsage()); dump.put(KEY_MEMORY, dumpMemory()); dump.put(KEY_DEFAULT_BROWSER_APP, dumpDefaultBrowser()); dump.put(KEY_ANOMALY_DETECTION, dumpAnomalyDetection()); } catch (Exception e) { Log.w(TAG, "exception in dump: ", e); } Loading Loading @@ -197,20 +195,6 @@ public class SettingsDumpService extends Service { } } @VisibleForTesting JSONObject dumpAnomalyDetection() throws JSONException { final JSONObject obj = new JSONObject(); final SharedPreferences sharedPreferences = getSharedPreferences( AnomalyConfigJobService.PREF_DB, Context.MODE_PRIVATE); final int currentVersion = sharedPreferences.getInt( AnomalyConfigJobService.KEY_ANOMALY_CONFIG_VERSION, 0 /* defValue */); obj.put("anomaly_config_version", String.valueOf(currentVersion)); return obj; } private void dumpMobileNetworkSettings(IndentingPrintWriter writer) { MobileNetworkRepository.getInstance(this).dump(writer); } Loading src/com/android/settings/fuelgauge/batterytip/AnomalyCleanupJobService.javadeleted 100644 → 0 +0 −80 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.batterytip; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settingslib.utils.ThreadUtils; import java.util.concurrent.TimeUnit; /** A JobService to clean up obsolete data in anomaly database */ public class AnomalyCleanupJobService extends JobService { private static final String TAG = "AnomalyCleanUpJobService"; @VisibleForTesting static final long CLEAN_UP_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1); public static void scheduleCleanUp(Context context) { final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); final ComponentName component = new ComponentName(context, AnomalyCleanupJobService.class); final JobInfo.Builder jobBuilder = new JobInfo.Builder(R.integer.job_anomaly_clean_up, component) .setPeriodic(CLEAN_UP_FREQUENCY_MS) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .setPersisted(true); final JobInfo pending = jobScheduler.getPendingJob(R.integer.job_anomaly_clean_up); // Don't schedule it if it already exists, to make sure it runs periodically even after // reboot if (pending == null && jobScheduler.schedule(jobBuilder.build()) != JobScheduler.RESULT_SUCCESS) { Log.i(TAG, "Anomaly clean up job service schedule failed."); } } @Override public boolean onStartJob(JobParameters params) { final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager.getInstance(this); final BatteryTipPolicy policy = new BatteryTipPolicy(this); ThreadUtils.postOnBackgroundThread( () -> { batteryDatabaseManager.deleteAllAnomaliesBeforeTimeStamp( System.currentTimeMillis() - TimeUnit.DAYS.toMillis(policy.dataHistoryRetainDay)); jobFinished(params, false /* wantsReschedule */); }); return true; } @Override public boolean onStopJob(JobParameters jobParameters) { return false; } } src/com/android/settings/fuelgauge/batterytip/AnomalyConfigJobService.javadeleted 100644 → 0 +0 −139 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.batterytip; import android.app.StatsManager; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences; import android.provider.Settings; import android.text.TextUtils; import android.util.Base64; import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settingslib.utils.ThreadUtils; import java.util.concurrent.TimeUnit; /** A JobService check whether to update the anomaly config periodically */ public class AnomalyConfigJobService extends JobService { private static final String TAG = "AnomalyConfigJobService"; public static final String PREF_DB = "anomaly_pref"; public static final String KEY_ANOMALY_CONFIG_VERSION = "anomaly_config_version"; private static final int DEFAULT_VERSION = 0; @VisibleForTesting static final long CONFIG_UPDATE_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1); public static void scheduleConfigUpdate(Context context) { final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); final ComponentName component = new ComponentName(context, AnomalyConfigJobService.class); final JobInfo.Builder jobBuilder = new JobInfo.Builder(R.integer.job_anomaly_config_update, component) .setPeriodic(CONFIG_UPDATE_FREQUENCY_MS) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .setPersisted(true); final JobInfo pending = jobScheduler.getPendingJob(R.integer.job_anomaly_config_update); // Don't schedule it if it already exists, to make sure it runs periodically even after // reboot if (pending == null && jobScheduler.schedule(jobBuilder.build()) != JobScheduler.RESULT_SUCCESS) { Log.i(TAG, "Anomaly config update job service schedule failed."); } } @Override public boolean onStartJob(JobParameters params) { ThreadUtils.postOnBackgroundThread( () -> { final StatsManager statsManager = getSystemService(StatsManager.class); checkAnomalyConfig(statsManager); try { BatteryTipUtils.uploadAnomalyPendingIntent(this, statsManager); } catch (StatsManager.StatsUnavailableException e) { Log.w(TAG, "Failed to uploadAnomalyPendingIntent.", e); } jobFinished(params, false /* wantsReschedule */); }); return true; } @Override public boolean onStopJob(JobParameters jobParameters) { return false; } @VisibleForTesting synchronized void checkAnomalyConfig(StatsManager statsManager) { final SharedPreferences sharedPreferences = getSharedPreferences(PREF_DB, Context.MODE_PRIVATE); final int currentVersion = sharedPreferences.getInt(KEY_ANOMALY_CONFIG_VERSION, DEFAULT_VERSION); final int newVersion = Settings.Global.getInt( getContentResolver(), Settings.Global.ANOMALY_CONFIG_VERSION, DEFAULT_VERSION); final String rawConfig = Settings.Global.getString(getContentResolver(), Settings.Global.ANOMALY_CONFIG); Log.i(TAG, "CurrentVersion: " + currentVersion + " new version: " + newVersion); if (newVersion > currentVersion) { try { statsManager.removeConfig(StatsManagerConfig.ANOMALY_CONFIG_KEY); } catch (StatsManager.StatsUnavailableException e) { Log.i( TAG, "When updating anomaly config, failed to first remove the old config " + StatsManagerConfig.ANOMALY_CONFIG_KEY, e); } if (!TextUtils.isEmpty(rawConfig)) { try { final byte[] config = Base64.decode(rawConfig, Base64.DEFAULT); statsManager.addConfig(StatsManagerConfig.ANOMALY_CONFIG_KEY, config); Log.i( TAG, "Upload the anomaly config. configKey: " + StatsManagerConfig.ANOMALY_CONFIG_KEY); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putInt(KEY_ANOMALY_CONFIG_VERSION, newVersion); editor.commit(); } catch (IllegalArgumentException e) { Log.e(TAG, "Anomaly raw config is in wrong format", e); } catch (StatsManager.StatsUnavailableException e) { Log.i( TAG, "Upload of anomaly config failed for configKey " + StatsManagerConfig.ANOMALY_CONFIG_KEY, e); } } } } } src/com/android/settings/fuelgauge/batterytip/AnomalyConfigReceiver.javadeleted 100644 → 0 +0 −52 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.batterytip; import android.app.StatsManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; /** * Receive broadcast when {@link StatsManager} restart, then check the anomaly config and prepare * info for {@link StatsManager} */ public class AnomalyConfigReceiver extends BroadcastReceiver { private static final String TAG = "AnomalyConfigReceiver"; @Override public void onReceive(Context context, Intent intent) { if (StatsManager.ACTION_STATSD_STARTED.equals(intent.getAction()) || Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { final StatsManager statsManager = context.getSystemService(StatsManager.class); // Check whether to update the config AnomalyConfigJobService.scheduleConfigUpdate(context); try { BatteryTipUtils.uploadAnomalyPendingIntent(context, statsManager); } catch (StatsManager.StatsUnavailableException e) { Log.w(TAG, "Failed to uploadAnomalyPendingIntent.", e); } if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { AnomalyCleanupJobService.scheduleCleanUp(context); } } } } Loading
AndroidManifest.xml +0 −14 Original line number Diff line number Diff line Loading @@ -4692,20 +4692,6 @@ android:permission="android.permission.MANAGE_SLICE_PERMISSIONS" android:exported="true" /> <!-- Couldn't be triggered from outside of settings. Statsd can trigger it because we send PendingIntent to it--> <receiver android:name=".fuelgauge.batterytip.AnomalyDetectionReceiver" android:exported="false" /> <service android:name=".fuelgauge.batterytip.AnomalyCleanupJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> <service android:name=".fuelgauge.batterytip.AnomalyConfigJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> <service android:name=".fuelgauge.batterytip.AnomalyDetectionJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> <provider android:name=".homepage.contextualcards.CardContentProvider" android:authorities="${applicationId}.homepage.CardContentProvider" Loading
src/com/android/settings/SettingsDumpService.java +0 −16 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import androidx.annotation.VisibleForTesting; import com.android.settings.applications.ProcStatsData; import com.android.settings.datausage.lib.DataUsageLib; import com.android.settings.fuelgauge.batterytip.AnomalyConfigJobService; import com.android.settings.network.MobileNetworkRepository; import com.android.settingslib.net.DataUsageController; Loading Loading @@ -99,7 +98,6 @@ public class SettingsDumpService extends Service { dump.put(KEY_DATAUSAGE, dumpDataUsage()); dump.put(KEY_MEMORY, dumpMemory()); dump.put(KEY_DEFAULT_BROWSER_APP, dumpDefaultBrowser()); dump.put(KEY_ANOMALY_DETECTION, dumpAnomalyDetection()); } catch (Exception e) { Log.w(TAG, "exception in dump: ", e); } Loading Loading @@ -197,20 +195,6 @@ public class SettingsDumpService extends Service { } } @VisibleForTesting JSONObject dumpAnomalyDetection() throws JSONException { final JSONObject obj = new JSONObject(); final SharedPreferences sharedPreferences = getSharedPreferences( AnomalyConfigJobService.PREF_DB, Context.MODE_PRIVATE); final int currentVersion = sharedPreferences.getInt( AnomalyConfigJobService.KEY_ANOMALY_CONFIG_VERSION, 0 /* defValue */); obj.put("anomaly_config_version", String.valueOf(currentVersion)); return obj; } private void dumpMobileNetworkSettings(IndentingPrintWriter writer) { MobileNetworkRepository.getInstance(this).dump(writer); } Loading
src/com/android/settings/fuelgauge/batterytip/AnomalyCleanupJobService.javadeleted 100644 → 0 +0 −80 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.batterytip; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settingslib.utils.ThreadUtils; import java.util.concurrent.TimeUnit; /** A JobService to clean up obsolete data in anomaly database */ public class AnomalyCleanupJobService extends JobService { private static final String TAG = "AnomalyCleanUpJobService"; @VisibleForTesting static final long CLEAN_UP_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1); public static void scheduleCleanUp(Context context) { final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); final ComponentName component = new ComponentName(context, AnomalyCleanupJobService.class); final JobInfo.Builder jobBuilder = new JobInfo.Builder(R.integer.job_anomaly_clean_up, component) .setPeriodic(CLEAN_UP_FREQUENCY_MS) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .setPersisted(true); final JobInfo pending = jobScheduler.getPendingJob(R.integer.job_anomaly_clean_up); // Don't schedule it if it already exists, to make sure it runs periodically even after // reboot if (pending == null && jobScheduler.schedule(jobBuilder.build()) != JobScheduler.RESULT_SUCCESS) { Log.i(TAG, "Anomaly clean up job service schedule failed."); } } @Override public boolean onStartJob(JobParameters params) { final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager.getInstance(this); final BatteryTipPolicy policy = new BatteryTipPolicy(this); ThreadUtils.postOnBackgroundThread( () -> { batteryDatabaseManager.deleteAllAnomaliesBeforeTimeStamp( System.currentTimeMillis() - TimeUnit.DAYS.toMillis(policy.dataHistoryRetainDay)); jobFinished(params, false /* wantsReschedule */); }); return true; } @Override public boolean onStopJob(JobParameters jobParameters) { return false; } }
src/com/android/settings/fuelgauge/batterytip/AnomalyConfigJobService.javadeleted 100644 → 0 +0 −139 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.batterytip; import android.app.StatsManager; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences; import android.provider.Settings; import android.text.TextUtils; import android.util.Base64; import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settingslib.utils.ThreadUtils; import java.util.concurrent.TimeUnit; /** A JobService check whether to update the anomaly config periodically */ public class AnomalyConfigJobService extends JobService { private static final String TAG = "AnomalyConfigJobService"; public static final String PREF_DB = "anomaly_pref"; public static final String KEY_ANOMALY_CONFIG_VERSION = "anomaly_config_version"; private static final int DEFAULT_VERSION = 0; @VisibleForTesting static final long CONFIG_UPDATE_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1); public static void scheduleConfigUpdate(Context context) { final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); final ComponentName component = new ComponentName(context, AnomalyConfigJobService.class); final JobInfo.Builder jobBuilder = new JobInfo.Builder(R.integer.job_anomaly_config_update, component) .setPeriodic(CONFIG_UPDATE_FREQUENCY_MS) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .setPersisted(true); final JobInfo pending = jobScheduler.getPendingJob(R.integer.job_anomaly_config_update); // Don't schedule it if it already exists, to make sure it runs periodically even after // reboot if (pending == null && jobScheduler.schedule(jobBuilder.build()) != JobScheduler.RESULT_SUCCESS) { Log.i(TAG, "Anomaly config update job service schedule failed."); } } @Override public boolean onStartJob(JobParameters params) { ThreadUtils.postOnBackgroundThread( () -> { final StatsManager statsManager = getSystemService(StatsManager.class); checkAnomalyConfig(statsManager); try { BatteryTipUtils.uploadAnomalyPendingIntent(this, statsManager); } catch (StatsManager.StatsUnavailableException e) { Log.w(TAG, "Failed to uploadAnomalyPendingIntent.", e); } jobFinished(params, false /* wantsReschedule */); }); return true; } @Override public boolean onStopJob(JobParameters jobParameters) { return false; } @VisibleForTesting synchronized void checkAnomalyConfig(StatsManager statsManager) { final SharedPreferences sharedPreferences = getSharedPreferences(PREF_DB, Context.MODE_PRIVATE); final int currentVersion = sharedPreferences.getInt(KEY_ANOMALY_CONFIG_VERSION, DEFAULT_VERSION); final int newVersion = Settings.Global.getInt( getContentResolver(), Settings.Global.ANOMALY_CONFIG_VERSION, DEFAULT_VERSION); final String rawConfig = Settings.Global.getString(getContentResolver(), Settings.Global.ANOMALY_CONFIG); Log.i(TAG, "CurrentVersion: " + currentVersion + " new version: " + newVersion); if (newVersion > currentVersion) { try { statsManager.removeConfig(StatsManagerConfig.ANOMALY_CONFIG_KEY); } catch (StatsManager.StatsUnavailableException e) { Log.i( TAG, "When updating anomaly config, failed to first remove the old config " + StatsManagerConfig.ANOMALY_CONFIG_KEY, e); } if (!TextUtils.isEmpty(rawConfig)) { try { final byte[] config = Base64.decode(rawConfig, Base64.DEFAULT); statsManager.addConfig(StatsManagerConfig.ANOMALY_CONFIG_KEY, config); Log.i( TAG, "Upload the anomaly config. configKey: " + StatsManagerConfig.ANOMALY_CONFIG_KEY); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putInt(KEY_ANOMALY_CONFIG_VERSION, newVersion); editor.commit(); } catch (IllegalArgumentException e) { Log.e(TAG, "Anomaly raw config is in wrong format", e); } catch (StatsManager.StatsUnavailableException e) { Log.i( TAG, "Upload of anomaly config failed for configKey " + StatsManagerConfig.ANOMALY_CONFIG_KEY, e); } } } } }
src/com/android/settings/fuelgauge/batterytip/AnomalyConfigReceiver.javadeleted 100644 → 0 +0 −52 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.batterytip; import android.app.StatsManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; /** * Receive broadcast when {@link StatsManager} restart, then check the anomaly config and prepare * info for {@link StatsManager} */ public class AnomalyConfigReceiver extends BroadcastReceiver { private static final String TAG = "AnomalyConfigReceiver"; @Override public void onReceive(Context context, Intent intent) { if (StatsManager.ACTION_STATSD_STARTED.equals(intent.getAction()) || Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { final StatsManager statsManager = context.getSystemService(StatsManager.class); // Check whether to update the config AnomalyConfigJobService.scheduleConfigUpdate(context); try { BatteryTipUtils.uploadAnomalyPendingIntent(context, statsManager); } catch (StatsManager.StatsUnavailableException e) { Log.w(TAG, "Failed to uploadAnomalyPendingIntent.", e); } if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { AnomalyCleanupJobService.scheduleCleanUp(context); } } } }