Record app optimization mode backup into BatteryHistoricalLog
App optimization mode format:
https://screenshot.googleplex.com/di9DDzBfYf7ihfV
App optimization mode backup format:
https://screenshot.googleplex.com/GkVW5HrgGvmv5yh
Bug: 192523697
Test: make SettingsRoboTests
Change-Id: I60a9a76a8ffc89d625ee3f77c138a19181c81c38
diff --git a/protos/fuelgauge_log.proto b/protos/fuelgauge_log.proto
index cf87dc7..8512cb8 100644
--- a/protos/fuelgauge_log.proto
+++ b/protos/fuelgauge_log.proto
@@ -19,10 +19,11 @@
APPLY = 2;
RESET = 3;
RESTORE = 4;
+ BACKUP = 5;
}
optional string package_name = 1;
optional Action action = 2;
optional string action_description = 3;
optional int64 timestamp = 4;
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
index 0558d46..79df57a 100644
--- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
@@ -22,6 +22,7 @@
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupHelper;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.IDeviceIdleController;
@@ -34,9 +35,11 @@
import androidx.annotation.VisibleForTesting;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import java.io.IOException;
+import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -47,6 +50,8 @@
/** An inditifier for {@link BackupHelper}. */
public static final String TAG = "BatteryBackupHelper";
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
+ private static final String BATTERY_OPTIMIZE_BACKUP_FILE_NAME =
+ "battery_optimize_backup_historical_logs";
static final String DELIMITER = ",";
static final String DELIMITER_MODE = ":";
@@ -141,6 +146,7 @@
int backupCount = 0;
final StringBuilder builder = new StringBuilder();
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+ final SharedPreferences sharedPreferences = getSharedPreferences(mContext);
// Converts application into the AppUsageState.
for (ApplicationInfo info : applications) {
final int mode = BatteryOptimizeUtils.getMode(appOps, info.uid, info.packageName);
@@ -157,6 +163,9 @@
info.packageName + DELIMITER_MODE + optimizationMode;
builder.append(packageOptimizeMode + DELIMITER);
Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode);
+ BatteryHistoricalLogUtil.writeLog(
+ sharedPreferences, Action.BACKUP, info.packageName,
+ /* actionDescription */ "mode: " + optimizationMode);
backupCount++;
}
@@ -210,6 +219,18 @@
restoreCount, (System.currentTimeMillis() - timestamp)));
}
+ /** Dump the app optimization mode backup history data. */
+ public static void dumpHistoricalData(Context context, PrintWriter writer) {
+ BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(
+ getSharedPreferences(context), writer);
+ }
+
+ @VisibleForTesting
+ static SharedPreferences getSharedPreferences(Context context) {
+ return context.getSharedPreferences(
+ BATTERY_OPTIMIZE_BACKUP_FILE_NAME, Context.MODE_PRIVATE);
+ }
+
private void restoreOptimizationMode(
String packageName, @BatteryOptimizeUtils.OptimizationMode int mode) {
final int uid = BatteryUtils.getInstance(mContext).getPackageUid(packageName);
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java b/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java
index a827e6d..f82b703 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java
@@ -37,40 +37,40 @@
@VisibleForTesting
static final int MAX_ENTRIES = 40;
- /**
- * Writes a log entry.
- *
- * <p>Keeps up to {@link #MAX_ENTRIES} in the log, once that number is exceeded, it prunes the
- * oldest one.
- */
- static void writeLog(Context context, Action action, String pkg, String actionDescription) {
+ /** Writes a log entry for battery optimization mode. */
+ static void writeLog(
+ Context context, Action action, String packageName, String actionDescription) {
+ writeLog(getSharedPreferences(context), action, packageName, actionDescription);
+ }
+
+ static void writeLog(SharedPreferences sharedPreferences, Action action,
+ String packageName, String actionDescription) {
writeLog(
- context,
+ sharedPreferences,
BatteryOptimizeHistoricalLogEntry.newBuilder()
- .setPackageName(pkg)
+ .setPackageName(packageName)
.setAction(action)
.setActionDescription(actionDescription)
.setTimestamp(System.currentTimeMillis())
.build());
}
- private static void writeLog(Context context, BatteryOptimizeHistoricalLogEntry logEntry) {
- SharedPreferences sharedPreferences = getSharedPreferences(context);
-
+ private static void writeLog(
+ SharedPreferences sharedPreferences, BatteryOptimizeHistoricalLogEntry logEntry) {
BatteryOptimizeHistoricalLog existingLog =
parseLogFromString(sharedPreferences.getString(LOGS_KEY, ""));
BatteryOptimizeHistoricalLog.Builder newLogBuilder = existingLog.toBuilder();
- // Prune old entries
+ // Prune old entries to limit the max logging data count.
if (existingLog.getLogEntryCount() >= MAX_ENTRIES) {
newLogBuilder.removeLogEntry(0);
}
newLogBuilder.addLogEntry(logEntry);
+ String loggingContent =
+ Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT);
sharedPreferences
.edit()
- .putString(
- LOGS_KEY,
- Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT))
+ .putString(LOGS_KEY, loggingContent)
.apply();
}
@@ -79,34 +79,36 @@
storedLogs, BatteryOptimizeHistoricalLog.getDefaultInstance());
}
- /**
- * Prints the historical log that has previously been stored by this utility.
- */
+ /** Prints the historical log that has previously been stored by this utility. */
public static void printBatteryOptimizeHistoricalLog(Context context, PrintWriter writer) {
+ printBatteryOptimizeHistoricalLog(getSharedPreferences(context), writer);
+ }
+
+ /** Prints the historical log that has previously been stored by this utility. */
+ public static void printBatteryOptimizeHistoricalLog(
+ SharedPreferences sharedPreferences, PrintWriter writer) {
writer.println("Battery optimize state history:");
- SharedPreferences sharedPreferences = getSharedPreferences(context);
BatteryOptimizeHistoricalLog existingLog =
parseLogFromString(sharedPreferences.getString(LOGS_KEY, ""));
List<BatteryOptimizeHistoricalLogEntry> logEntryList = existingLog.getLogEntryList();
if (logEntryList.isEmpty()) {
- writer.println("\tNo past logs.");
+ writer.println("\tnothing to dump");
} else {
- writer.println("0:RESTRICTED 1:UNRESTRICTED 2:OPTIMIZED 3:UNKNOWN");
+ writer.println("0:UNKNOWN 1:RESTRICTED 2:UNRESTRICTED 3:OPTIMIZED");
logEntryList.forEach(entry -> writer.println(toString(entry)));
}
}
- /**
- * Gets the unique key for logging, combined with package name, delimiter and user id.
- */
- static String getPackageNameWithUserId(String pkgName, int userId) {
- return pkgName + ":" + userId;
+ /** Gets the unique key for logging. */
+ static String getPackageNameWithUserId(String packageName, int userId) {
+ return packageName + ":" + userId;
}
private static String toString(BatteryOptimizeHistoricalLogEntry entry) {
- return String.format("%s\tAction:%s\tEvent:%s\tTimestamp:%s", entry.getPackageName(),
- entry.getAction(), entry.getActionDescription(),
- ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()));
+ return String.format("%s\t%s\taction:%s\tevent:%s",
+ ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()),
+ entry.getPackageName(), entry.getAction(),
+ entry.getActionDescription());
}
@VisibleForTesting
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index f3d6816..8970730 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -70,6 +70,8 @@
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -84,6 +86,8 @@
private static final int UID1 = 1;
private Context mContext;
+ private PrintWriter mPrintWriter;
+ private StringWriter mStringWriter;
private BatteryBackupHelper mBatteryBackupHelper;
@Mock
@@ -109,6 +113,8 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mStringWriter = new StringWriter();
+ mPrintWriter = new PrintWriter(mStringWriter);
doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
@@ -126,6 +132,7 @@
@After
public void resetShadows() {
ShadowUserHandle.reset();
+ BatteryBackupHelper.getSharedPreferences(mContext).edit().clear().apply();
}
@Test
@@ -216,6 +223,8 @@
// 2 for UNRESTRICTED mode and 1 for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME1 + ":2," + PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult);
+ verifyDumpHistoryData("com.android.testing.1\taction:BACKUP\tevent:mode: 2");
+ verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
}
@Test
@@ -232,6 +241,7 @@
// "com.android.testing.2" for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult);
+ verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
}
@Test
@@ -248,6 +258,7 @@
// "com.android.testing.2" for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult);
+ verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
}
@Test
@@ -357,6 +368,11 @@
doReturn(dataKey).when(mBackupDataInputStream).getKey();
}
+ private void verifyDumpHistoryData(String expectedResult) {
+ BatteryBackupHelper.dumpHistoricalData(mContext, mPrintWriter);
+ assertThat(mStringWriter.toString().contains(expectedResult)).isTrue();
+ }
+
private void verifyBackupData(String expectedResult) throws Exception {
final byte[] expectedBytes = expectedResult.getBytes();
final ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java
index 74f62ad..cb5de7d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java
@@ -49,7 +49,7 @@
@Test
public void printHistoricalLog_withDefaultLogs() {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
- assertThat(mTestStringWriter.toString()).contains("No past logs");
+ assertThat(mTestStringWriter.toString()).contains("nothing to dump");
}
@Test
@@ -58,7 +58,7 @@
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString()).contains(
- "pkg1\tAction:APPLY\tEvent:logs\tTimestamp:");
+ "pkg1\taction:APPLY\tevent:logs");
}
@Test