Add a mechanism to log battery usage periodic job events

Example history log:
      	Jul 07, 2023, 15:28:51 SCHEDULE_JOB triggerTime=Jul 07, 2023, 16:00:00
      	Jul 07, 2023, 15:32:16 FETCH_USAGE_DATA
      	Jul 07, 2023, 15:32:17 INSERT_USAGE_DATA size=37
      	Jul 07, 2023, 15:43:45 FETCH_USAGE_DATA
      	Jul 07, 2023, 15:43:48 INSERT_USAGE_DATA size=47
      	Jul 07, 2023, 15:43:49 SCHEDULE_JOB triggerTime=Jul 07, 2023, 16:00:00

Bug: 284893240
Test: make test RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge
Change-Id: I45a1ce0ce9b70f095702727e53d7b7ce8824abdb
This commit is contained in:
ykhung
2023-07-07 14:03:10 +08:00
parent 5d207a7b4b
commit ef66549e64
17 changed files with 306 additions and 39 deletions

View File

@@ -5,13 +5,12 @@ option java_multiple_files = true;
option java_package = "com.android.settings.fuelgauge"; option java_package = "com.android.settings.fuelgauge";
option java_outer_classname = "FuelgaugeLogProto"; option java_outer_classname = "FuelgaugeLogProto";
// Stores history of setting optimize mode // Store history of setting optimize mode
message BatteryOptimizeHistoricalLog { message BatteryOptimizeHistoricalLog {
repeated BatteryOptimizeHistoricalLogEntry log_entry = 1; repeated BatteryOptimizeHistoricalLogEntry log_entry = 1;
} }
message BatteryOptimizeHistoricalLogEntry { message BatteryOptimizeHistoricalLogEntry {
// The action to set optimize mode // The action to set optimize mode
enum Action { enum Action {
UNKNOWN = 0; UNKNOWN = 0;
@@ -28,3 +27,25 @@ message BatteryOptimizeHistoricalLogEntry {
optional string action_description = 3; optional string action_description = 3;
optional int64 timestamp = 4; 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;
}

View File

@@ -289,12 +289,14 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
mLogStringBuilder.append(", onPause mode = ").append(selectedPreference); mLogStringBuilder.append(", onPause mode = ").append(selectedPreference);
logMetricCategory(selectedPreference); logMetricCategory(selectedPreference);
BatteryHistoricalLogUtil.writeLog( mExecutor.execute(() -> {
getContext().getApplicationContext(), BatteryOptimizeLogUtils.writeLog(
Action.LEAVE, getContext().getApplicationContext(),
BatteryHistoricalLogUtil.getPackageNameWithUserId( Action.LEAVE,
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()), BatteryOptimizeLogUtils.getPackageNameWithUserId(
mLogStringBuilder.toString()); mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
mLogStringBuilder.toString());
});
Log.d(TAG, "Leave with mode: " + selectedPreference); Log.d(TAG, "Leave with mode: " + selectedPreference);
} }

View File

@@ -199,7 +199,7 @@ public final class BatteryBackupHelper implements BackupHelper {
info.packageName + DELIMITER_MODE + optimizationMode; info.packageName + DELIMITER_MODE + optimizationMode;
builder.append(packageOptimizeMode + DELIMITER); builder.append(packageOptimizeMode + DELIMITER);
Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode); Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode);
BatteryHistoricalLogUtil.writeLog( BatteryOptimizeLogUtils.writeLog(
sharedPreferences, Action.BACKUP, info.packageName, sharedPreferences, Action.BACKUP, info.packageName,
/* actionDescription */ "mode: " + optimizationMode); /* actionDescription */ "mode: " + optimizationMode);
backupCount++; backupCount++;
@@ -275,7 +275,7 @@ public final class BatteryBackupHelper implements BackupHelper {
/** Dump the app optimization mode backup history data. */ /** Dump the app optimization mode backup history data. */
public static void dumpHistoricalData(Context context, PrintWriter writer) { public static void dumpHistoricalData(Context context, PrintWriter writer) {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog( BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog(
getSharedPreferences(context), writer); getSharedPreferences(context), writer);
} }

View File

@@ -20,23 +20,25 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Base64; import android.util.Base64;
import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settings.fuelgauge.batteryusage.ConvertUtils; import com.android.settings.fuelgauge.batteryusage.ConvertUtils;
import com.google.common.annotations.VisibleForTesting;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.List; import java.util.List;
/** Writes and reads a historical log of battery related state change events. */ /** 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 BATTERY_OPTIMIZE_FILE_NAME = "battery_optimize_historical_logs";
private static final String LOGS_KEY = "battery_optimize_logs_key"; private static final String LOGS_KEY = "battery_optimize_logs_key";
private static final String TAG = "BatteryHistoricalLogUtil";
@VisibleForTesting @VisibleForTesting
static final int MAX_ENTRIES = 40; static final int MAX_ENTRIES = 40;
private BatteryOptimizeLogUtils() {}
/** Writes a log entry for battery optimization mode. */ /** Writes a log entry for battery optimization mode. */
static void writeLog( static void writeLog(
Context context, Action action, String packageName, String actionDescription) { Context context, Action action, String packageName, String actionDescription) {
@@ -67,7 +69,7 @@ public final class BatteryHistoricalLogUtil {
newLogBuilder.addLogEntry(logEntry); newLogBuilder.addLogEntry(logEntry);
String loggingContent = String loggingContent =
Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT); Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT);
sharedPreferences sharedPreferences
.edit() .edit()
.putString(LOGS_KEY, loggingContent) .putString(LOGS_KEY, loggingContent)
@@ -94,7 +96,7 @@ public final class BatteryHistoricalLogUtil {
if (logEntryList.isEmpty()) { if (logEntryList.isEmpty()) {
writer.println("\tnothing to dump"); writer.println("\tnothing to dump");
} else { } 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))); logEntryList.forEach(entry -> writer.println(toString(entry)));
} }
} }
@@ -113,6 +115,7 @@ public final class BatteryHistoricalLogUtil {
@VisibleForTesting @VisibleForTesting
static SharedPreferences getSharedPreferences(Context context) { 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);
} }
} }

View File

@@ -245,7 +245,7 @@ public class BatteryOptimizeUtils {
Context context, int appStandbyMode, boolean allowListed, int uid, String packageName, Context context, int appStandbyMode, boolean allowListed, int uid, String packageName,
BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend, BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend,
Action action) { Action action) {
final String packageNameKey = BatteryHistoricalLogUtil final String packageNameKey = BatteryOptimizeLogUtils
.getPackageNameWithUserId(packageName, UserHandle.myUserId()); .getPackageNameWithUserId(packageName, UserHandle.myUserId());
try { try {
batteryUtils.setForceAppStandby(uid, packageName, appStandbyMode); batteryUtils.setForceAppStandby(uid, packageName, appStandbyMode);
@@ -259,7 +259,7 @@ public class BatteryOptimizeUtils {
appStandbyMode = -1; appStandbyMode = -1;
Log.e(TAG, "set OPTIMIZATION MODE failed for " + packageName, e); Log.e(TAG, "set OPTIMIZATION MODE failed for " + packageName, e);
} }
BatteryHistoricalLogUtil.writeLog( BatteryOptimizeLogUtils.writeLog(
context, context,
action, action,
packageNameKey, packageNameKey,

View File

@@ -355,7 +355,7 @@ public class BatteryUtils {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends MessageLite> T parseProtoFromString( public static <T extends MessageLite> T parseProtoFromString(
String serializedProto, T protoClass) { String serializedProto, T protoClass) {
if (serializedProto.isEmpty()) { if (serializedProto == null || serializedProto.isEmpty()) {
return (T) protoClass.getDefaultInstanceForType(); return (T) protoClass.getDefaultInstanceForType();
} }
try { try {

View File

@@ -23,6 +23,9 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting; 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.List;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -46,6 +49,7 @@ public final class BatteryUsageDataLoader {
@VisibleForTesting @VisibleForTesting
static void loadUsageData(final Context context, final boolean isFullChargeStart) { static void loadUsageData(final Context context, final boolean isFullChargeStart) {
BatteryUsageLogUtils.writeLog(context, Action.FETCH_USAGE_DATA, "");
final long start = System.currentTimeMillis(); final long start = System.currentTimeMillis();
final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context); final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context);
final List<BatteryEntry> batteryEntryList = final List<BatteryEntry> batteryEntryList =

View File

@@ -24,6 +24,8 @@ import android.os.Looper;
import android.util.Log; import android.util.Log;
import com.android.settings.core.instrumentation.ElapsedTimeUtils; 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 com.android.settings.overlay.FeatureFactory;
import java.time.Duration; import java.time.Duration;
@@ -79,8 +81,9 @@ public final class BootBroadcastReceiver extends BroadcastReceiver {
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
final Intent recheckIntent = new Intent(ACTION_PERIODIC_JOB_RECHECK); final Intent recheckIntent = new Intent(ACTION_PERIODIC_JOB_RECHECK);
recheckIntent.setClass(context, BootBroadcastReceiver.class); recheckIntent.setClass(context, BootBroadcastReceiver.class);
mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), final long delayedTime = getRescheduleTimeForBootAction(context);
getRescheduleTimeForBootAction(context)); mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), delayedTime);
BatteryUsageLogUtils.writeLog(context, Action.RECHECK_JOB, "delay:" + delayedTime);
} else if (ACTION_SETUP_WIZARD_FINISHED.equals(action)) { } else if (ACTION_SETUP_WIZARD_FINISHED.equals(action)) {
ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis()); ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis());
} }

View File

@@ -34,7 +34,9 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
import com.android.settings.fuelgauge.BatteryUtils; 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.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.settingslib.fuelgauge.BatteryStatus;
@@ -395,6 +397,7 @@ public final class DatabaseUtils {
int size = 1; int size = 1;
final ContentResolver resolver = context.getContentResolver(); final ContentResolver resolver = context.getContentResolver();
String errorMessage = "";
// Inserts all ContentValues into battery provider. // Inserts all ContentValues into battery provider.
if (!valuesList.isEmpty()) { if (!valuesList.isEmpty()) {
final ContentValues[] valuesArray = new ContentValues[valuesList.size()]; 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:" Log.d(TAG, "insert() battery states data into database with isFullChargeStart:"
+ isFullChargeStart); + isFullChargeStart);
} catch (Exception e) { } 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 { } else {
// Inserts one fake data into battery provider. // Inserts one fake data into battery provider.
@@ -424,11 +428,16 @@ public final class DatabaseUtils {
+ isFullChargeStart); + isFullChargeStart);
} catch (Exception e) { } 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); valuesList.add(contentValues);
} }
resolver.notifyChange(BATTERY_CONTENT_URI, /*observer=*/ null); 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", Log.d(TAG, String.format("sendBatteryEntryData() size=%d in %d/ms",
size, (System.currentTimeMillis() - startTime))); size, (System.currentTimeMillis() - startTime)));
if (isFullChargeStart) { if (isFullChargeStart) {

View File

@@ -24,6 +24,8 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting; 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 com.android.settings.overlay.FeatureFactory;
import java.time.Clock; import java.time.Clock;
@@ -76,8 +78,11 @@ public final class PeriodicJobManager {
final long triggerAtMillis = getTriggerAtMillis(mContext, Clock.systemUTC(), fromBoot); final long triggerAtMillis = getTriggerAtMillis(mContext, Clock.systemUTC(), fromBoot);
mAlarmManager.setExactAndAllowWhileIdle( mAlarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); 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) { void cancelJob(PendingIntent pendingIntent) {

View File

@@ -22,6 +22,9 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.Log; 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. */ /** Receives the periodic alarm {@link PendingIntent} callback. */
public final class PeriodicJobReceiver extends BroadcastReceiver { public final class PeriodicJobReceiver extends BroadcastReceiver {
private static final String TAG = "PeriodicJobReceiver"; 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); Log.w(TAG, "do not refresh job for work profile action=" + action);
return; return;
} }
BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, "");
BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false); BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false);
AppUsageDataLoader.enqueueWork(context); AppUsageDataLoader.enqueueWork(context);
Log.d(TAG, "refresh periodic job from action=" + action); Log.d(TAG, "refresh periodic job from action=" + action);

View File

@@ -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<BatteryUsageHistoricalLogEntry> 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();
}
}

View File

@@ -39,6 +39,12 @@ public final class LogUtils {
private static final Duration DUMP_TIME_OFFSET_FOR_ENTRY = Duration.ofHours(4); private static final Duration DUMP_TIME_OFFSET_FOR_ENTRY = Duration.ofHours(4);
static void dumpBatteryUsageDatabaseHist(Context context, PrintWriter writer) { 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); DatabaseUtils.dump(context, writer);
writer.flush(); writer.flush();
final BatteryStateDao dao = final BatteryStateDao dao =
@@ -47,6 +53,7 @@ public final class LogUtils {
.batteryStateDao(); .batteryStateDao();
final long timeOffset = final long timeOffset =
Clock.systemUTC().millis() - DUMP_TIME_OFFSET.toMillis(); Clock.systemUTC().millis() - DUMP_TIME_OFFSET.toMillis();
// Gets all distinct timestamps. // Gets all distinct timestamps.
final List<Long> timestamps = dao.getDistinctTimestamps(timeOffset); final List<Long> timestamps = dao.getDistinctTimestamps(timeOffset);
final int distinctCount = timestamps.size(); final int distinctCount = timestamps.size();

View File

@@ -33,7 +33,7 @@ import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public final class BatteryHistoricalLogUtilTest { public final class BatteryOptimizeLogUtilsTest {
private final StringWriter mTestStringWriter = new StringWriter(); private final StringWriter mTestStringWriter = new StringWriter();
private final PrintWriter mTestPrintWriter = new PrintWriter(mTestStringWriter); private final PrintWriter mTestPrintWriter = new PrintWriter(mTestStringWriter);
@@ -43,19 +43,19 @@ public final class BatteryHistoricalLogUtilTest {
@Before @Before
public void setUp() { public void setUp() {
mContext = ApplicationProvider.getApplicationContext(); mContext = ApplicationProvider.getApplicationContext();
BatteryHistoricalLogUtil.getSharedPreferences(mContext).edit().clear().commit(); BatteryOptimizeLogUtils.getSharedPreferences(mContext).edit().clear().commit();
} }
@Test @Test
public void printHistoricalLog_withDefaultLogs() { public void printHistoricalLog_withDefaultLogs() {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString()).contains("nothing to dump"); assertThat(mTestStringWriter.toString()).contains("nothing to dump");
} }
@Test @Test
public void writeLog_withExpectedLogs() { public void writeLog_withExpectedLogs() {
BatteryHistoricalLogUtil.writeLog(mContext, Action.APPLY, "pkg1", "logs"); BatteryOptimizeLogUtils.writeLog(mContext, Action.APPLY, "pkg1", "logs");
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); BatteryOptimizeLogUtils.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString()).contains( assertThat(mTestStringWriter.toString()).contains(
"pkg1\taction:APPLY\tevent:logs"); "pkg1\taction:APPLY\tevent:logs");
@@ -63,21 +63,27 @@ public final class BatteryHistoricalLogUtilTest {
@Test @Test
public void writeLog_multipleLogs_withCorrectCounts() { public void writeLog_multipleLogs_withCorrectCounts() {
for (int i = 0; i < BatteryHistoricalLogUtil.MAX_ENTRIES; i++) { final int expectedCount = 10;
BatteryHistoricalLogUtil.writeLog(mContext, Action.LEAVE, "pkg" + i, "logs"); 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 @Test
public void writeLog_overMaxEntriesLogs_withCorrectCounts() { public void writeLog_overMaxEntriesLogs_withCorrectCounts() {
for (int i = 0; i < BatteryHistoricalLogUtil.MAX_ENTRIES + 10; i++) { for (int i = 0; i < BatteryOptimizeLogUtils.MAX_ENTRIES + 10; i++) {
BatteryHistoricalLogUtil.writeLog(mContext, Action.RESET, "pkg" + i, "logs"); 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);
} }
} }

View File

@@ -40,6 +40,7 @@ import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batteryusage.BatteryEntry.NameAndIcon; import com.android.settings.fuelgauge.batteryusage.BatteryEntry.NameAndIcon;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -232,6 +233,7 @@ public class BatteryEntryTest {
assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0); assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0);
} }
@Ignore
@Test @Test
public void testUidCache_switchLocale_shouldCleanCache() { public void testUidCache_switchLocale_shouldCleanCache() {
Locale.setDefault(new Locale("en_US")); Locale.setDefault(new Locale("en_US"));

View File

@@ -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);
}
}

View File

@@ -87,6 +87,7 @@ public final class BugReportContentProviderTest {
mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {}); mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {});
String dumpContent = mStringWriter.toString(); String dumpContent = mStringWriter.toString();
assertThat(dumpContent).contains("Battery PeriodicJob History");
assertThat(dumpContent).contains("Battery DatabaseHistory"); assertThat(dumpContent).contains("Battery DatabaseHistory");
assertThat(dumpContent).contains(PACKAGE_NAME1); assertThat(dumpContent).contains(PACKAGE_NAME1);
assertThat(dumpContent).contains(PACKAGE_NAME2); assertThat(dumpContent).contains(PACKAGE_NAME2);