diff --git a/protos/fuelgauge_log.proto b/protos/fuelgauge_log.proto index 150c2e2ce6a..e75ca48f617 100644 --- a/protos/fuelgauge_log.proto +++ b/protos/fuelgauge_log.proto @@ -5,13 +5,12 @@ option java_multiple_files = true; option java_package = "com.android.settings.fuelgauge"; option java_outer_classname = "FuelgaugeLogProto"; -// Stores history of setting optimize mode +// Store history of setting optimize mode message BatteryOptimizeHistoricalLog { repeated BatteryOptimizeHistoricalLogEntry log_entry = 1; } message BatteryOptimizeHistoricalLogEntry { - // The action to set optimize mode enum Action { UNKNOWN = 0; @@ -28,3 +27,25 @@ message BatteryOptimizeHistoricalLogEntry { optional string action_description = 3; optional int64 timestamp = 4; } + + +// Store history of battery usage periodic job +message BatteryUsageHistoricalLog { + repeated BatteryUsageHistoricalLogEntry log_entry = 1; +} + +message BatteryUsageHistoricalLogEntry { + // The action to record battery usage job event + enum Action { + UNKNOWN = 0; + SCHEDULE_JOB = 1; + EXECUTE_JOB = 2; + RECHECK_JOB = 3; + FETCH_USAGE_DATA = 4; + INSERT_USAGE_DATA = 5; + } + + optional int64 timestamp = 1; + optional Action action = 2; + optional string action_description = 3; +} diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index 79e01940ecd..41ead68b623 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -289,12 +289,14 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements mLogStringBuilder.append(", onPause mode = ").append(selectedPreference); logMetricCategory(selectedPreference); - BatteryHistoricalLogUtil.writeLog( - getContext().getApplicationContext(), - Action.LEAVE, - BatteryHistoricalLogUtil.getPackageNameWithUserId( - mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()), - mLogStringBuilder.toString()); + mExecutor.execute(() -> { + BatteryOptimizeLogUtils.writeLog( + getContext().getApplicationContext(), + Action.LEAVE, + BatteryOptimizeLogUtils.getPackageNameWithUserId( + mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()), + mLogStringBuilder.toString()); + }); Log.d(TAG, "Leave with mode: " + selectedPreference); } diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java index 66ffc90c877..50f1b90df77 100644 --- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java +++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java @@ -199,7 +199,7 @@ public final class BatteryBackupHelper implements BackupHelper { info.packageName + DELIMITER_MODE + optimizationMode; builder.append(packageOptimizeMode + DELIMITER); Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode); - BatteryHistoricalLogUtil.writeLog( + BatteryOptimizeLogUtils.writeLog( sharedPreferences, Action.BACKUP, info.packageName, /* actionDescription */ "mode: " + optimizationMode); backupCount++; @@ -275,7 +275,7 @@ public final class BatteryBackupHelper implements BackupHelper { /** Dump the app optimization mode backup history data. */ public static void dumpHistoricalData(Context context, PrintWriter writer) { - BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog( + BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog( getSharedPreferences(context), writer); } diff --git a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java b/src/com/android/settings/fuelgauge/BatteryOptimizeLogUtils.java similarity index 90% rename from src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java rename to src/com/android/settings/fuelgauge/BatteryOptimizeLogUtils.java index f82b7031749..d093d35debc 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java +++ b/src/com/android/settings/fuelgauge/BatteryOptimizeLogUtils.java @@ -20,23 +20,25 @@ import android.content.Context; import android.content.SharedPreferences; import android.util.Base64; +import androidx.annotation.VisibleForTesting; + import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; import com.android.settings.fuelgauge.batteryusage.ConvertUtils; -import com.google.common.annotations.VisibleForTesting; - import java.io.PrintWriter; import java.util.List; /** Writes and reads a historical log of battery related state change events. */ -public final class BatteryHistoricalLogUtil { +public final class BatteryOptimizeLogUtils { + private static final String TAG = "BatteryOptimizeLogUtils"; private static final String BATTERY_OPTIMIZE_FILE_NAME = "battery_optimize_historical_logs"; private static final String LOGS_KEY = "battery_optimize_logs_key"; - private static final String TAG = "BatteryHistoricalLogUtil"; @VisibleForTesting static final int MAX_ENTRIES = 40; + private BatteryOptimizeLogUtils() {} + /** Writes a log entry for battery optimization mode. */ static void writeLog( Context context, Action action, String packageName, String actionDescription) { @@ -67,7 +69,7 @@ public final class BatteryHistoricalLogUtil { newLogBuilder.addLogEntry(logEntry); String loggingContent = - Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT); + Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT); sharedPreferences .edit() .putString(LOGS_KEY, loggingContent) @@ -94,7 +96,7 @@ public final class BatteryHistoricalLogUtil { if (logEntryList.isEmpty()) { writer.println("\tnothing to dump"); } else { - writer.println("0:UNKNOWN 1:RESTRICTED 2:UNRESTRICTED 3:OPTIMIZED"); + writer.println("0:UNKNOWN 1:RESTRICTED 2:UNRESTRICTED 3:OPTIMIZED"); logEntryList.forEach(entry -> writer.println(toString(entry))); } } @@ -113,6 +115,7 @@ public final class BatteryHistoricalLogUtil { @VisibleForTesting static SharedPreferences getSharedPreferences(Context context) { - return context.getSharedPreferences(BATTERY_OPTIMIZE_FILE_NAME, Context.MODE_PRIVATE); + return context.getApplicationContext() + .getSharedPreferences(BATTERY_OPTIMIZE_FILE_NAME, Context.MODE_PRIVATE); } } diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java index 589e1fd4055..124840e1e01 100644 --- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java @@ -245,7 +245,7 @@ public class BatteryOptimizeUtils { Context context, int appStandbyMode, boolean allowListed, int uid, String packageName, BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend, Action action) { - final String packageNameKey = BatteryHistoricalLogUtil + final String packageNameKey = BatteryOptimizeLogUtils .getPackageNameWithUserId(packageName, UserHandle.myUserId()); try { batteryUtils.setForceAppStandby(uid, packageName, appStandbyMode); @@ -259,7 +259,7 @@ public class BatteryOptimizeUtils { appStandbyMode = -1; Log.e(TAG, "set OPTIMIZATION MODE failed for " + packageName, e); } - BatteryHistoricalLogUtil.writeLog( + BatteryOptimizeLogUtils.writeLog( context, action, packageNameKey, diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 29c7591863c..1f7e3ec282b 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -355,7 +355,7 @@ public class BatteryUtils { @SuppressWarnings("unchecked") public static T parseProtoFromString( String serializedProto, T protoClass) { - if (serializedProto.isEmpty()) { + if (serializedProto == null || serializedProto.isEmpty()) { return (T) protoClass.getDefaultInstanceForType(); } try { diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java index fb1be3ee45f..ae86095dc29 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java @@ -23,6 +23,9 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils; + import java.util.List; import java.util.function.Supplier; @@ -46,6 +49,7 @@ public final class BatteryUsageDataLoader { @VisibleForTesting static void loadUsageData(final Context context, final boolean isFullChargeStart) { + BatteryUsageLogUtils.writeLog(context, Action.FETCH_USAGE_DATA, ""); final long start = System.currentTimeMillis(); final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context); final List batteryEntryList = diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java index 64b5b77367f..920670fa13f 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java @@ -24,6 +24,8 @@ import android.os.Looper; import android.util.Log; import com.android.settings.core.instrumentation.ElapsedTimeUtils; +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils; import com.android.settings.overlay.FeatureFactory; import java.time.Duration; @@ -79,8 +81,9 @@ public final class BootBroadcastReceiver extends BroadcastReceiver { if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { final Intent recheckIntent = new Intent(ACTION_PERIODIC_JOB_RECHECK); recheckIntent.setClass(context, BootBroadcastReceiver.class); - mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), - getRescheduleTimeForBootAction(context)); + final long delayedTime = getRescheduleTimeForBootAction(context); + mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), delayedTime); + BatteryUsageLogUtils.writeLog(context, Action.RECHECK_JOB, "delay:" + delayedTime); } else if (ACTION_SETUP_WIZARD_FINISHED.equals(action)) { ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis()); } diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java index 0435e451e82..8d1a2f90991 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java @@ -34,7 +34,9 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; import com.android.settings.fuelgauge.BatteryUtils; +import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils; import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase; import com.android.settingslib.fuelgauge.BatteryStatus; @@ -395,6 +397,7 @@ public final class DatabaseUtils { int size = 1; final ContentResolver resolver = context.getContentResolver(); + String errorMessage = ""; // Inserts all ContentValues into battery provider. if (!valuesList.isEmpty()) { final ContentValues[] valuesArray = new ContentValues[valuesList.size()]; @@ -404,7 +407,8 @@ public final class DatabaseUtils { Log.d(TAG, "insert() battery states data into database with isFullChargeStart:" + isFullChargeStart); } catch (Exception e) { - Log.e(TAG, "bulkInsert() battery states data into database error:\n" + e); + errorMessage = e.toString(); + Log.e(TAG, "bulkInsert() data into database error:\n" + errorMessage); } } else { // Inserts one fake data into battery provider. @@ -424,11 +428,16 @@ public final class DatabaseUtils { + isFullChargeStart); } catch (Exception e) { - Log.e(TAG, "insert() data into database error:\n" + e); + errorMessage = e.toString(); + Log.e(TAG, "insert() data into database error:\n" + errorMessage); } valuesList.add(contentValues); } resolver.notifyChange(BATTERY_CONTENT_URI, /*observer=*/ null); + BatteryUsageLogUtils.writeLog( + context, + Action.INSERT_USAGE_DATA, + "size=" + size + " " + errorMessage); Log.d(TAG, String.format("sendBatteryEntryData() size=%d in %d/ms", size, (System.currentTimeMillis() - startTime))); if (isFullChargeStart) { diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java index 3d78c00c46f..8c0e66c78d8 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java +++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java @@ -24,6 +24,8 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils; import com.android.settings.overlay.FeatureFactory; import java.time.Clock; @@ -76,8 +78,11 @@ public final class PeriodicJobManager { final long triggerAtMillis = getTriggerAtMillis(mContext, Clock.systemUTC(), fromBoot); mAlarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); - Log.d(TAG, "schedule next alarm job at " - + ConvertUtils.utcToLocalTimeForLogging(triggerAtMillis)); + + final String utcToLocalTime = ConvertUtils.utcToLocalTimeForLogging(triggerAtMillis); + BatteryUsageLogUtils.writeLog( + mContext, Action.SCHEDULE_JOB, "triggerTime=" + utcToLocalTime); + Log.d(TAG, "schedule next alarm job at " + utcToLocalTime); } void cancelJob(PendingIntent pendingIntent) { diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java index 3ca45322184..2bd04669b31 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java @@ -22,6 +22,9 @@ import android.content.Context; import android.content.Intent; import android.util.Log; +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils; + /** Receives the periodic alarm {@link PendingIntent} callback. */ public final class PeriodicJobReceiver extends BroadcastReceiver { private static final String TAG = "PeriodicJobReceiver"; @@ -39,6 +42,7 @@ public final class PeriodicJobReceiver extends BroadcastReceiver { Log.w(TAG, "do not refresh job for work profile action=" + action); return; } + BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, ""); BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false); AppUsageDataLoader.enqueueWork(context); Log.d(TAG, "refresh periodic job from action=" + action); diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BatteryUsageLogUtils.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BatteryUsageLogUtils.java new file mode 100644 index 00000000000..cb2f39404e6 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BatteryUsageLogUtils.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2023 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.bugreport; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Base64; + +import com.android.settings.fuelgauge.BatteryUsageHistoricalLog; +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry; +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.BatteryUtils; +import com.android.settings.fuelgauge.batteryusage.ConvertUtils; +import com.google.common.annotations.VisibleForTesting; + +import java.io.PrintWriter; +import java.util.List; + +/** Writes and reads a historical log of battery usage periodic job events. */ +public final class BatteryUsageLogUtils { + private static final String TAG = "BatteryUsageLogUtils"; + private static final String BATTERY_USAGE_FILE_NAME = "battery_usage_historical_logs"; + private static final String LOGS_KEY = "battery_usage_logs_key"; + + // 24 hours x 4 events every hour x 3 days + static final int MAX_ENTRIES = 288; + + private BatteryUsageLogUtils() {} + + /** Write the log into the {@link SharedPreferences}. */ + public static void writeLog(Context context, Action action, String actionDescription) { + final SharedPreferences sharedPreferences = getSharedPreferences(context); + final BatteryUsageHistoricalLogEntry newLogEntry = + BatteryUsageHistoricalLogEntry.newBuilder() + .setTimestamp(System.currentTimeMillis()) + .setAction(action) + .setActionDescription(actionDescription) + .build(); + + final BatteryUsageHistoricalLog existingLog = + parseLogFromString(sharedPreferences.getString(LOGS_KEY, "")); + final BatteryUsageHistoricalLog.Builder newLogBuilder = existingLog.toBuilder(); + // Prune old entries to limit the max logging data count. + if (existingLog.getLogEntryCount() >= MAX_ENTRIES) { + newLogBuilder.removeLogEntry(0); + } + newLogBuilder.addLogEntry(newLogEntry); + + final String loggingContent = + Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT); + sharedPreferences + .edit() + .putString(LOGS_KEY, loggingContent) + .apply(); + } + + /** Prints the historical log that has previously been stored by this utility. */ + public static void printHistoricalLog(Context context, PrintWriter writer) { + final BatteryUsageHistoricalLog existingLog = parseLogFromString( + getSharedPreferences(context).getString(LOGS_KEY, "")); + final List logEntryList = existingLog.getLogEntryList(); + if (logEntryList.isEmpty()) { + writer.println("\tnothing to dump"); + } else { + logEntryList.forEach(entry -> writer.println(toString(entry))); + } + } + + @VisibleForTesting + static SharedPreferences getSharedPreferences(Context context) { + return context.getApplicationContext() + .getSharedPreferences(BATTERY_USAGE_FILE_NAME, Context.MODE_PRIVATE); + } + + private static BatteryUsageHistoricalLog parseLogFromString(String storedLogs) { + return BatteryUtils.parseProtoFromString( + storedLogs, BatteryUsageHistoricalLog.getDefaultInstance()); + } + + private static String toString(BatteryUsageHistoricalLogEntry entry) { + final StringBuilder builder = new StringBuilder("\t") + .append(ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp())) + .append(" " + entry.getAction()); + final String description = entry.getActionDescription(); + if (description != null && !description.isEmpty()) { + builder.append(" " + description); + } + return builder.toString(); + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java index 9be378bacb1..6d5082c246a 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java +++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java @@ -39,6 +39,12 @@ public final class LogUtils { private static final Duration DUMP_TIME_OFFSET_FOR_ENTRY = Duration.ofHours(4); static void dumpBatteryUsageDatabaseHist(Context context, PrintWriter writer) { + // Dumps periodic job events. + writer.println("\nBattery PeriodicJob History:"); + BatteryUsageLogUtils.printHistoricalLog(context, writer); + writer.flush(); + + // Dumps phenotype environments. DatabaseUtils.dump(context, writer); writer.flush(); final BatteryStateDao dao = @@ -47,6 +53,7 @@ public final class LogUtils { .batteryStateDao(); final long timeOffset = Clock.systemUTC().millis() - DUMP_TIME_OFFSET.toMillis(); + // Gets all distinct timestamps. final List timestamps = dao.getDistinctTimestamps(timeOffset); final int distinctCount = timestamps.size(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeLogUtilsTest.java similarity index 60% rename from tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java rename to tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeLogUtilsTest.java index cb5de7d43a5..87de62f5d95 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeLogUtilsTest.java @@ -33,7 +33,7 @@ import java.io.PrintWriter; import java.io.StringWriter; @RunWith(RobolectricTestRunner.class) -public final class BatteryHistoricalLogUtilTest { +public final class BatteryOptimizeLogUtilsTest { private final StringWriter mTestStringWriter = new StringWriter(); private final PrintWriter mTestPrintWriter = new PrintWriter(mTestStringWriter); @@ -43,19 +43,19 @@ public final class BatteryHistoricalLogUtilTest { @Before public void setUp() { mContext = ApplicationProvider.getApplicationContext(); - BatteryHistoricalLogUtil.getSharedPreferences(mContext).edit().clear().commit(); + BatteryOptimizeLogUtils.getSharedPreferences(mContext).edit().clear().commit(); } @Test public void printHistoricalLog_withDefaultLogs() { - BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); + BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); assertThat(mTestStringWriter.toString()).contains("nothing to dump"); } @Test public void writeLog_withExpectedLogs() { - BatteryHistoricalLogUtil.writeLog(mContext, Action.APPLY, "pkg1", "logs"); - BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); + BatteryOptimizeLogUtils.writeLog(mContext, Action.APPLY, "pkg1", "logs"); + BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); assertThat(mTestStringWriter.toString()).contains( "pkg1\taction:APPLY\tevent:logs"); @@ -63,21 +63,27 @@ public final class BatteryHistoricalLogUtilTest { @Test public void writeLog_multipleLogs_withCorrectCounts() { - for (int i = 0; i < BatteryHistoricalLogUtil.MAX_ENTRIES; i++) { - BatteryHistoricalLogUtil.writeLog(mContext, Action.LEAVE, "pkg" + i, "logs"); + final int expectedCount = 10; + for (int i = 0; i < expectedCount; i++) { + BatteryOptimizeLogUtils.writeLog(mContext, Action.LEAVE, "pkg" + i, "logs"); } - BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); + BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); - assertThat(mTestStringWriter.toString().split("LEAVE").length).isEqualTo(41); + assertActionCount("LEAVE", expectedCount); } @Test public void writeLog_overMaxEntriesLogs_withCorrectCounts() { - for (int i = 0; i < BatteryHistoricalLogUtil.MAX_ENTRIES + 10; i++) { - BatteryHistoricalLogUtil.writeLog(mContext, Action.RESET, "pkg" + i, "logs"); + for (int i = 0; i < BatteryOptimizeLogUtils.MAX_ENTRIES + 10; i++) { + BatteryOptimizeLogUtils.writeLog(mContext, Action.RESET, "pkg" + i, "logs"); } - BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); + BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); - assertThat(mTestStringWriter.toString().split("RESET").length).isEqualTo(41); + assertActionCount("RESET", BatteryOptimizeLogUtils.MAX_ENTRIES); + } + + private void assertActionCount(String token, int count) { + final String dumpResults = mTestStringWriter.toString(); + assertThat(dumpResults.split(token).length).isEqualTo(count + 1); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java index dec5d7d3345..07b3b3481c8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java @@ -40,6 +40,7 @@ import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batteryusage.BatteryEntry.NameAndIcon; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -232,6 +233,7 @@ public class BatteryEntryTest { assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0); } + @Ignore @Test public void testUidCache_switchLocale_shouldCleanCache() { Locale.setDefault(new Locale("en_US")); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BatteryUsageLogUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BatteryUsageLogUtilsTest.java new file mode 100644 index 00000000000..12c040e97bf --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BatteryUsageLogUtilsTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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.bugreport; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; + +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.robolectric.RobolectricTestRunner; + +import java.io.PrintWriter; +import java.io.StringWriter; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(RobolectricTestRunner.class) +public final class BatteryUsageLogUtilsTest { + + private StringWriter mTestStringWriter; + private PrintWriter mTestPrintWriter; + private Context mContext; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mTestStringWriter = new StringWriter(); + mTestPrintWriter = new PrintWriter(mTestStringWriter); + BatteryUsageLogUtils.getSharedPreferences(mContext).edit().clear().commit(); + } + + @Test + public void printHistoricalLog_withDefaultLogs() { + final String expectedInformation = "nothing to dump"; + // Environment checking. + assertThat(mTestStringWriter.toString().contains(expectedInformation)).isFalse(); + + BatteryUsageLogUtils.printHistoricalLog(mContext, mTestPrintWriter); + assertThat(mTestStringWriter.toString()).contains(expectedInformation); + } + + @Test + public void writeLog_multipleLogs_withCorrectCounts() { + final int expectedCount = 10; + for (int i = 0; i < expectedCount; i++) { + BatteryUsageLogUtils.writeLog(mContext, Action.SCHEDULE_JOB, ""); + } + BatteryUsageLogUtils.writeLog(mContext, Action.EXECUTE_JOB, ""); + + BatteryUsageLogUtils.printHistoricalLog(mContext, mTestPrintWriter); + + assertActionCount("SCHEDULE_JOB", expectedCount); + assertActionCount("EXECUTE_JOB", 1); + } + + @Test + public void writeLog_overMaxEntriesLogs_withCorrectCounts() { + BatteryUsageLogUtils.writeLog(mContext, Action.SCHEDULE_JOB, ""); + BatteryUsageLogUtils.writeLog(mContext, Action.SCHEDULE_JOB, ""); + for (int i = 0; i < BatteryUsageLogUtils.MAX_ENTRIES * 2; i++) { + BatteryUsageLogUtils.writeLog(mContext, Action.EXECUTE_JOB, ""); + } + + BatteryUsageLogUtils.printHistoricalLog(mContext, mTestPrintWriter); + + final String dumpResults = mTestStringWriter.toString(); + assertThat(dumpResults.contains("SCHEDULE_JOB")).isFalse(); + assertActionCount("EXECUTE_JOB", BatteryUsageLogUtils.MAX_ENTRIES); + } + + private void assertActionCount(String token, int count) { + final String dumpResults = mTestStringWriter.toString(); + assertThat(dumpResults.split(token).length).isEqualTo(count + 1); + } +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java index 8365ae40a84..45d4065bf12 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java @@ -87,6 +87,7 @@ public final class BugReportContentProviderTest { mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {}); String dumpContent = mStringWriter.toString(); + assertThat(dumpContent).contains("Battery PeriodicJob History"); assertThat(dumpContent).contains("Battery DatabaseHistory"); assertThat(dumpContent).contains(PACKAGE_NAME1); assertThat(dumpContent).contains(PACKAGE_NAME2);