From 798340fafdb3bf9aa83e89b22a7a73ece429955e Mon Sep 17 00:00:00 2001 From: mxyyiyi Date: Wed, 8 May 2024 17:08:16 +0800 Subject: [PATCH] Update database clear & job refresh mechanism for time change intent - Ignore time change intent for time format update - Clear data after current time in DB and refresh periodic job - Take a snapshot of current battery usage stats if no periodic job in DB Bug: 336423923 Bug: 314921894 Fix: 314921894 Test: atest SettingsRoboTests:com.android.settings.fuelgauge.batteryusagei Change-Id: Iec0f5e8e97f18c4603de711a5884336ba0af23a9 --- .../batteryusage/BootBroadcastReceiver.java | 2 +- .../fuelgauge/batteryusage/DatabaseUtils.java | 62 ++++++++++--------- .../batteryusage/db/AppUsageEventDao.java | 4 ++ .../batteryusage/db/BatteryEventDao.java | 4 ++ .../batteryusage/db/BatteryStateDao.java | 4 ++ .../batteryusage/db/BatteryUsageSlotDao.java | 4 ++ .../BootBroadcastReceiverTest.java | 43 +++++++++++-- 7 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java index e407c636ddf..5fa04eb0959 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java @@ -67,7 +67,7 @@ public final class BootBroadcastReceiver extends BroadcastReceiver { refreshJobs(context); break; case Intent.ACTION_TIME_CHANGED: - Log.d(TAG, "refresh job and clear all data from action=" + action); + Log.d(TAG, "refresh job and clear data from action=" + action); DatabaseUtils.clearDataAfterTimeChangedIfNeeded(context, intent); break; default: diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java index a41e9bd0388..b40f71ac16e 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java @@ -16,8 +16,6 @@ package com.android.settings.fuelgauge.batteryusage; -import static android.content.Intent.FLAG_RECEIVER_REPLACE_PENDING; - import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTimeForLogging; import android.app.usage.IUsageStatsManager; @@ -436,6 +434,23 @@ public final class DatabaseUtils { }); } + /** Clears data after a specific startTimestamp in the battery usage database. */ + public static void clearAllAfter(Context context, long startTimestamp) { + AsyncTask.execute( + () -> { + try { + final BatteryStateDatabase database = + BatteryStateDatabase.getInstance(context.getApplicationContext()); + database.appUsageEventDao().clearAllAfter(startTimestamp); + database.batteryEventDao().clearAllAfter(startTimestamp); + database.batteryStateDao().clearAllAfter(startTimestamp); + database.batteryUsageSlotDao().clearAllAfter(startTimestamp); + } catch (RuntimeException e) { + Log.e(TAG, "clearAllAfter() failed", e); + } + }); + } + /** Clears all out-of-date data in the battery usage database. */ public static void clearExpiredDataIfNeeded(Context context) { AsyncTask.execute( @@ -456,14 +471,14 @@ public final class DatabaseUtils { }); } - /** Clears all data and jobs if current timestamp is out of the range of last recorded job. */ + /** Clears data after new updated time and refresh periodic job. */ public static void clearDataAfterTimeChangedIfNeeded(Context context, Intent intent) { - if ((intent.getFlags() & FLAG_RECEIVER_REPLACE_PENDING) != 0) { + if ((intent.hasExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT))) { BatteryUsageLogUtils.writeLog( context, Action.TIME_UPDATED, - "Database is not cleared because the time change intent is only" - + " for the existing pending receiver."); + "Database is not cleared because the time change intent is" + + " for time format change"); return; } AsyncTask.execute( @@ -861,36 +876,23 @@ public final class DatabaseUtils { } private static void clearDataAfterTimeChangedIfNeededInternal(Context context) { + final long currentTime = System.currentTimeMillis(); + final String logInfo = + String.format(Locale.ENGLISH, "clear data after current time = %d", currentTime); + Log.d(TAG, logInfo); + BatteryUsageLogUtils.writeLog(context, Action.TIME_UPDATED, logInfo); + DatabaseUtils.clearAllAfter(context, currentTime); + PeriodicJobManager.getInstance(context).refreshJob(/* fromBoot= */ false); + final List batteryLevelRecordEvents = DatabaseUtils.getBatteryEvents( context, Calendar.getInstance(), getLastFullChargeTime(context), BATTERY_LEVEL_RECORD_EVENTS); - final long lastRecordTimestamp = - batteryLevelRecordEvents.isEmpty() - ? INVALID_TIMESTAMP - : batteryLevelRecordEvents.get(0).getTimestamp(); - final long nextRecordTimestamp = - TimestampUtils.getNextEvenHourTimestamp(lastRecordTimestamp); - final long currentTime = System.currentTimeMillis(); - final boolean isOutOfTimeRange = - lastRecordTimestamp == INVALID_TIMESTAMP - || currentTime < lastRecordTimestamp - || currentTime > nextRecordTimestamp; - final String logInfo = - String.format( - Locale.ENGLISH, - "clear database = %b, current time = %d, last record time = %d", - isOutOfTimeRange, - currentTime, - lastRecordTimestamp); - Log.d(TAG, logInfo); - BatteryUsageLogUtils.writeLog(context, Action.TIME_UPDATED, logInfo); - if (isOutOfTimeRange) { - DatabaseUtils.clearAll(context); - PeriodicJobManager.getInstance(context) - .refreshJob(/* fromBoot= */ false); + if (batteryLevelRecordEvents.isEmpty()) { + // Take a snapshot of battery usage data immediately if there's no battery events. + BatteryUsageDataLoader.enqueueWork(context, /* isFullChargeStart= */ true); } } diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java index d220b15968f..249780125f2 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java +++ b/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java @@ -55,6 +55,10 @@ public interface AppUsageEventDao { @Query("DELETE FROM AppUsageEventEntity WHERE timestamp <= :timestamp") void clearAllBefore(long timestamp); + /** Deletes all recorded data after a specific timestamp. */ + @Query("DELETE FROM AppUsageEventEntity WHERE timestamp >= :timestamp") + void clearAllAfter(long timestamp); + /** Clears all recorded data in the database. */ @Query("DELETE FROM AppUsageEventEntity") void clearAll(); diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java index 8b696fe96c0..19d20438afa 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java +++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java @@ -65,6 +65,10 @@ public interface BatteryEventDao { @Query("DELETE FROM BatteryEventEntity WHERE timestamp <= :timestamp") void clearAllBefore(long timestamp); + /** Deletes all recorded data after a specific timestamp. */ + @Query("DELETE FROM BatteryEventEntity WHERE timestamp >= :timestamp") + void clearAllAfter(long timestamp); + /** Clears all recorded data in the database. */ @Query("DELETE FROM BatteryEventEntity") void clearAll(); diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java index 520c6bed484..049251eb718 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java +++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java @@ -61,6 +61,10 @@ public interface BatteryStateDao { @Query("DELETE FROM BatteryState WHERE timestamp <= :timestamp") void clearAllBefore(long timestamp); + /** Deletes all recorded data after a specific timestamp. */ + @Query("DELETE FROM BatteryState WHERE timestamp >= :timestamp") + void clearAllAfter(long timestamp); + /** Clears all recorded data in the database. */ @Query("DELETE FROM BatteryState") void clearAll(); diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java index d8cf41d0ce8..d53b0cf2532 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java +++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java @@ -52,6 +52,10 @@ public interface BatteryUsageSlotDao { @Query("DELETE FROM BatteryUsageSlotEntity WHERE timestamp <= :timestamp") void clearAllBefore(long timestamp); + /** Deletes all recorded data after a specific timestamp. */ + @Query("DELETE FROM BatteryUsageSlotEntity WHERE timestamp >= :timestamp") + void clearAllAfter(long timestamp); + /** Clears all recorded data in the database. */ @Query("DELETE FROM BatteryUsageSlotEntity") void clearAll(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java index df330a36ac5..3e53b036edd 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java @@ -35,7 +35,6 @@ import com.android.settings.testutils.BatteryTestUtils; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -64,9 +63,8 @@ public final class BootBroadcastReceiverTest { // Inserts fake data into database for testing. final BatteryStateDatabase database = BatteryTestUtils.setUpBatteryStateDatabase(mContext); - BatteryTestUtils.insertDataToBatteryStateTable( - mContext, Clock.systemUTC().millis(), "com.android.systemui"); mDao = database.batteryStateDao(); + mDao.clearAll(); clearSharedPreferences(); } @@ -129,10 +127,13 @@ public final class BootBroadcastReceiverTest { assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull(); } - @Ignore("b/314921894") @Test - public void onReceive_withTimeChangedIntent_clearsAllDataAndRefreshesJob() + public void onReceive_withTimeChangedIntentSetEarlierTime_refreshesJob() throws InterruptedException { + BatteryTestUtils.insertDataToBatteryStateTable( + mContext, Clock.systemUTC().millis() + 60000, "com.android.systemui"); + assertThat(mDao.getAllAfter(0).size()).isEqualTo(1); + mReceiver.onReceive(mContext, new Intent(Intent.ACTION_TIME_CHANGED)); TimeUnit.MILLISECONDS.sleep(100); @@ -140,6 +141,38 @@ public final class BootBroadcastReceiverTest { assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNotNull(); } + @Test + public void onReceive_withTimeChangedIntentSetLaterTime_clearNoDataAndRefreshesJob() + throws InterruptedException { + BatteryTestUtils.insertDataToBatteryStateTable( + mContext, Clock.systemUTC().millis() - 60000, "com.android.systemui"); + assertThat(mDao.getAllAfter(0).size()).isEqualTo(1); + + mReceiver.onReceive(mContext, new Intent(Intent.ACTION_TIME_CHANGED)); + + TimeUnit.MILLISECONDS.sleep(100); + assertThat(mDao.getAllAfter(0).size()).isEqualTo(1); + assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNotNull(); + } + + @Test + public void onReceive_withTimeFormatChangedIntent_skipRefreshJob() throws InterruptedException { + BatteryTestUtils.insertDataToBatteryStateTable( + mContext, Clock.systemUTC().millis() + 60000, "com.android.systemui"); + assertThat(mDao.getAllAfter(0).size()).isEqualTo(1); + + mReceiver.onReceive( + mContext, + new Intent(Intent.EXTRA_INTENT) + .putExtra( + Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, + Intent.EXTRA_TIME_PREF_VALUE_USE_12_HOUR)); + + TimeUnit.MILLISECONDS.sleep(100); + assertThat(mDao.getAllAfter(0).size()).isEqualTo(1); + assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull(); + } + @Test public void invokeJobRecheck_broadcastsIntent() { BootBroadcastReceiver.invokeJobRecheck(mContext);