From 1f3cf084c8acad79e19da29cfb873f218a41ed61 Mon Sep 17 00:00:00 2001 From: ykhung Date: Sat, 25 Mar 2023 14:57:16 +0800 Subject: [PATCH] Record important battery usage event into SharedPreference for dump() Fix: 268300677 Test: presubmit Change-Id: If03106c265b984bc2608528bdf45386973e3a14f --- .../BatteryUsageBroadcastReceiver.java | 6 ++- .../batteryusage/BatteryUsageDataLoader.java | 4 ++ .../fuelgauge/batteryusage/DatabaseUtils.java | 53 ++++++++++++++++++- .../batteryusage/bugreport/LogUtils.java | 5 ++ .../BatteryUsageBroadcastReceiverTest.java | 18 +++++++ .../batteryusage/DatabaseUtilsTest.java | 35 ++++++++++++ 6 files changed, 118 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java index 9c7ec35fb4a..a437877df47 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java @@ -54,11 +54,13 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver { if (intent == null || intent.getAction() == null) { return; } - Log.d(TAG, "onReceive:" + intent.getAction()); + final String action = intent.getAction(); + Log.d(TAG, "onReceive:" + action); + DatabaseUtils.recordDateTime(context, action); final String fullChargeIntentAction = FeatureFactory.getFactory(context) .getPowerUsageFeatureProvider(context) .getFullChargeIntentAction(); - switch (intent.getAction()) { + switch (action) { case Intent.ACTION_BATTERY_LEVEL_CHANGED: // Only when fullChargeIntentAction is ACTION_BATTERY_LEVEL_CHANGED, // ACTION_BATTERY_LEVEL_CHANGED will be considered as the full charge event and then diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java index d446bb2b9c5..fb1be3ee45f 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java @@ -57,6 +57,10 @@ public final class BatteryUsageDataLoader { } final long elapsedTime = System.currentTimeMillis() - start; Log.d(TAG, String.format("getBatteryUsageStats() in %d/ms", elapsedTime)); + if (isFullChargeStart) { + DatabaseUtils.recordDateTime( + context, DatabaseUtils.KEY_LAST_LOAD_FULL_CHARGE_TIME); + } // Uploads the BatteryEntry data into database. DatabaseUtils.sendBatteryEntryData( diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java index 655114f4681..f1e72f07b05 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java @@ -19,6 +19,7 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; @@ -37,12 +38,16 @@ import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase; import com.android.settingslib.fuelgauge.BatteryStatus; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; import java.time.Clock; import java.time.Duration; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -50,12 +55,15 @@ import java.util.stream.Collectors; /** A utility class to operate battery usage database. */ public final class DatabaseUtils { private static final String TAG = "DatabaseUtils"; + private static final String SHARED_PREFS_FILE = "battery_usage_shared_prefs"; + /** Clear memory threshold for device booting phase. **/ private static final long CLEAR_MEMORY_THRESHOLD_MS = Duration.ofMinutes(5).toMillis(); private static final long CLEAR_MEMORY_DELAYED_MS = Duration.ofSeconds(2).toMillis(); - @VisibleForTesting static final int DATA_RETENTION_INTERVAL_DAY = 9; + static final String KEY_LAST_LOAD_FULL_CHARGE_TIME = "last_load_full_charge_time"; + static final String KEY_LAST_UPLOAD_FULL_CHARGE_TIME = "last_upload_full_charge_time"; /** An authority name of the battery content provider. */ public static final String AUTHORITY = "com.android.settings.battery.usage.provider"; @@ -373,10 +381,48 @@ public final class DatabaseUtils { resolver.notifyChange(BATTERY_CONTENT_URI, /*observer=*/ null); Log.d(TAG, String.format("sendBatteryEntryData() size=%d in %d/ms", size, (System.currentTimeMillis() - startTime))); + if (isFullChargeStart) { + recordDateTime(context, KEY_LAST_UPLOAD_FULL_CHARGE_TIME); + } clearMemory(); return valuesList; } + /** Dump all required data into {@link PrintWriter}. */ + public static void dump(Context context, PrintWriter writer) { + writeString(context, writer, "BatteryLevelChanged", + Intent.ACTION_BATTERY_LEVEL_CHANGED); + writeString(context, writer, "BatteryUnplugging", + BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING); + writeString(context, writer, "ClearBatteryCacheData", + BatteryUsageBroadcastReceiver.ACTION_CLEAR_BATTERY_CACHE_DATA); + writeString(context, writer, "LastLoadFullChargeTime", + KEY_LAST_LOAD_FULL_CHARGE_TIME); + writeString(context, writer, "LastUploadFullChargeTime", + KEY_LAST_UPLOAD_FULL_CHARGE_TIME); + } + + static SharedPreferences getSharedPreferences(Context context) { + return context.getApplicationContext().getSharedPreferences( + SHARED_PREFS_FILE, Context.MODE_PRIVATE); + } + + static void recordDateTime(Context context, String preferenceKey) { + final SharedPreferences sharedPreferences = getSharedPreferences(context); + if (sharedPreferences != null) { + sharedPreferences.edit().putString(preferenceKey, getCurrentDateTime()).apply(); + } + } + + private static void writeString( + Context context, PrintWriter writer, String prefix, String key) { + final SharedPreferences sharedPreferences = getSharedPreferences(context); + if (sharedPreferences != null) { + final String content = sharedPreferences.getString(key, ""); + writer.println(String.format("\t\t%s: %s", prefix, content)); + } + } + private static long loadAppUsageLatestTimestampFromContentProvider( Context context, final Uri appUsageLatestTimestampUri) { // We have already make sure the context here is with profile parent's user identity. Don't @@ -473,4 +519,9 @@ public final class DatabaseUtils { Log.w(TAG, "invoke clearMemory()"); }, CLEAR_MEMORY_DELAYED_MS); } + + private static String getCurrentDateTime() { + return new SimpleDateFormat("MMM dd,yyyy HH:mm:ss", Locale.getDefault()) + .format(new Date(System.currentTimeMillis())); + } } diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java index 82158394618..acf71ff4e95 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java @@ -19,6 +19,7 @@ package com.android.settings.fuelgauge.batteryusage.bugreport; import android.content.Context; import android.util.Log; +import com.android.settings.fuelgauge.batteryusage.DatabaseUtils; import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventDao; import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity; import com.android.settings.fuelgauge.batteryusage.db.BatteryState; @@ -41,6 +42,8 @@ public final class LogUtils { @SuppressWarnings("JavaUtilDate") static void dumpBatteryUsageDatabaseHist(Context context, PrintWriter writer) { + DatabaseUtils.dump(context, writer); + writer.flush(); final BatteryStateDao dao = BatteryStateDatabase .getInstance(context.getApplicationContext()) @@ -64,6 +67,7 @@ public final class LogUtils { writer.println("\t" + formattedTimestamp); Log.w(TAG, "\t" + formattedTimestamp); }); + writer.flush(); final List stateList = dao.getAllAfter( Clock.systemUTC().millis() - DUMP_TIME_OFFSET_FOR_ENTRY.toMillis()); @@ -80,6 +84,7 @@ public final class LogUtils { final List eventList = dao.getAllAfter( Clock.systemUTC().millis() - DUMP_TIME_OFFSET_FOR_ENTRY.toMillis()); eventList.stream().forEach(event -> writer.println(event)); + writer.flush(); } private LogUtils() {} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java index 60481975429..cb8a8862b66 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java @@ -57,6 +57,7 @@ public final class BatteryUsageBroadcastReceiverTest { mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mBatteryUsageBroadcastReceiver = new BatteryUsageBroadcastReceiver(); doReturn(mPackageManager).when(mContext).getPackageManager(); + DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply(); } @Test @@ -77,6 +78,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + assertSharedPreferences(Intent.ACTION_BATTERY_LEVEL_CHANGED); } @Test @@ -94,6 +96,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + assertSharedPreferences(Intent.ACTION_BATTERY_LEVEL_CHANGED); } @Test @@ -110,6 +113,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + assertSharedPreferences(Intent.ACTION_BATTERY_LEVEL_CHANGED); } @Test @@ -126,6 +130,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue(); + assertSharedPreferences(Intent.ACTION_BATTERY_LEVEL_CHANGED); } @Test @@ -139,6 +144,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + assertSharedPreferences(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING); } @Test @@ -156,6 +162,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + assertSharedPreferences(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING); } @Test @@ -172,6 +179,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse(); + assertSharedPreferences(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING); } @Test @@ -188,6 +196,7 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING)); assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isTrue(); + assertSharedPreferences(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING); } @Test @@ -202,6 +211,8 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(BatteryUsageBroadcastReceiver.ACTION_CLEAR_BATTERY_CACHE_DATA)); assertThat(BatteryDiffEntry.sValidForRestriction).isEmpty(); + assertSharedPreferences( + BatteryUsageBroadcastReceiver.ACTION_CLEAR_BATTERY_CACHE_DATA); } @Test @@ -216,6 +227,8 @@ public final class BatteryUsageBroadcastReceiverTest { new Intent(BatteryUsageBroadcastReceiver.ACTION_CLEAR_BATTERY_CACHE_DATA)); assertThat(BatteryDiffEntry.sValidForRestriction).isNotEmpty(); + assertSharedPreferences( + BatteryUsageBroadcastReceiver.ACTION_CLEAR_BATTERY_CACHE_DATA); } private static Intent getBatteryIntent(int level, int status) { @@ -225,4 +238,9 @@ public final class BatteryUsageBroadcastReceiverTest { intent.putExtra(BatteryManager.EXTRA_STATUS, status); return intent; } + + private void assertSharedPreferences(String preferenceKey) { + assertThat(DatabaseUtils.getSharedPreferences(mContext).contains(preferenceKey)) + .isTrue(); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java index 154497e8653..0cb3d1d50d4 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java @@ -46,6 +46,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -73,6 +75,7 @@ public final class DatabaseUtilsTest { doReturn(mMockContentResolver).when(mContext).getContentResolver(); doReturn(mPackageManager).when(mMockContext).getPackageManager(); doReturn(mPackageManager).when(mContext).getPackageManager(); + DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply(); } @Test @@ -396,6 +399,38 @@ public final class DatabaseUtilsTest { assertThat(batteryHistMap).isEmpty(); } + @Test + public void recordDateTime_writeDataIntoSharedPreferences() { + final String preferenceKey = "test_preference_key"; + DatabaseUtils.recordDateTime(mContext, preferenceKey); + + assertThat(DatabaseUtils.getSharedPreferences(mContext).contains(preferenceKey)) + .isTrue(); + } + + @Test + public void dump_dumpExpectedData() { + DatabaseUtils.recordDateTime(mContext, + Intent.ACTION_BATTERY_LEVEL_CHANGED); + DatabaseUtils.recordDateTime(mContext, + BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING); + DatabaseUtils.recordDateTime(mContext, + DatabaseUtils.KEY_LAST_LOAD_FULL_CHARGE_TIME); + DatabaseUtils.recordDateTime(mContext, + DatabaseUtils.KEY_LAST_UPLOAD_FULL_CHARGE_TIME); + final StringWriter stringWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(stringWriter); + + DatabaseUtils.dump(mContext, printWriter); + + String dumpContent = stringWriter.toString(); + assertThat(dumpContent.contains("BatteryLevelChanged")).isTrue(); + assertThat(dumpContent.contains("BatteryUnplugging")).isTrue(); + assertThat(dumpContent.contains("ClearBatteryCacheData")).isTrue(); + assertThat(dumpContent.contains("LastLoadFullChargeTime")).isTrue(); + assertThat(dumpContent.contains("LastUploadFullChargeTime")).isTrue(); + } + private static void verifyBatteryEntryContentValues( double consumedPower, ContentValues values) { final BatteryInformation batteryInformation =