Loading protos/fuelgauge_log.proto +2 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ message BatteryOptimizeHistoricalLogEntry { APPLY = 2; RESET = 3; RESTORE = 4; BACKUP = 5; } optional string package_name = 1; Loading src/com/android/settings/fuelgauge/BatteryBackupHelper.java +21 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.app.backup.BackupDataInputStream; 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; Loading @@ -34,9 +35,11 @@ import android.util.Log; 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; Loading @@ -47,6 +50,8 @@ public final class BatteryBackupHelper implements BackupHelper { /** 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 = ":"; Loading Loading @@ -141,6 +146,7 @@ public final class BatteryBackupHelper implements BackupHelper { 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); Loading @@ -157,6 +163,9 @@ public final class BatteryBackupHelper implements BackupHelper { 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++; } Loading Loading @@ -210,6 +219,18 @@ public final class BatteryBackupHelper implements BackupHelper { 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); Loading src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java +32 −30 Original line number Diff line number Diff line Loading @@ -37,40 +37,40 @@ public final class BatteryHistoricalLogUtil { @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(); } Loading @@ -79,34 +79,36 @@ public final class BatteryHistoricalLogUtil { 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 Loading tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java +16 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,8 @@ import org.robolectric.annotation.Implementation; 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; Loading @@ -84,6 +86,8 @@ public final class BatteryBackupHelperTest { private static final int UID1 = 1; private Context mContext; private PrintWriter mPrintWriter; private StringWriter mStringWriter; private BatteryBackupHelper mBatteryBackupHelper; @Mock Loading @@ -109,6 +113,8 @@ public final class BatteryBackupHelperTest { 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); Loading @@ -126,6 +132,7 @@ public final class BatteryBackupHelperTest { @After public void resetShadows() { ShadowUserHandle.reset(); BatteryBackupHelper.getSharedPreferences(mContext).edit().clear().apply(); } @Test Loading Loading @@ -216,6 +223,8 @@ public final class BatteryBackupHelperTest { // 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 Loading @@ -232,6 +241,7 @@ public final class BatteryBackupHelperTest { // "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 Loading @@ -248,6 +258,7 @@ public final class BatteryBackupHelperTest { // "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 Loading Loading @@ -357,6 +368,11 @@ public final class BatteryBackupHelperTest { 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); Loading tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public final class BatteryHistoricalLogUtilTest { @Test public void printHistoricalLog_withDefaultLogs() { BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); assertThat(mTestStringWriter.toString()).contains("No past logs"); assertThat(mTestStringWriter.toString()).contains("nothing to dump"); } @Test Loading @@ -58,7 +58,7 @@ public final class BatteryHistoricalLogUtilTest { BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); assertThat(mTestStringWriter.toString()).contains( "pkg1\tAction:APPLY\tEvent:logs\tTimestamp:"); "pkg1\taction:APPLY\tevent:logs"); } @Test Loading Loading
protos/fuelgauge_log.proto +2 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ message BatteryOptimizeHistoricalLogEntry { APPLY = 2; RESET = 3; RESTORE = 4; BACKUP = 5; } optional string package_name = 1; Loading
src/com/android/settings/fuelgauge/BatteryBackupHelper.java +21 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.app.backup.BackupDataInputStream; 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; Loading @@ -34,9 +35,11 @@ import android.util.Log; 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; Loading @@ -47,6 +50,8 @@ public final class BatteryBackupHelper implements BackupHelper { /** 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 = ":"; Loading Loading @@ -141,6 +146,7 @@ public final class BatteryBackupHelper implements BackupHelper { 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); Loading @@ -157,6 +163,9 @@ public final class BatteryBackupHelper implements BackupHelper { 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++; } Loading Loading @@ -210,6 +219,18 @@ public final class BatteryBackupHelper implements BackupHelper { 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); Loading
src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java +32 −30 Original line number Diff line number Diff line Loading @@ -37,40 +37,40 @@ public final class BatteryHistoricalLogUtil { @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(); } Loading @@ -79,34 +79,36 @@ public final class BatteryHistoricalLogUtil { 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 Loading
tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java +16 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,8 @@ import org.robolectric.annotation.Implementation; 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; Loading @@ -84,6 +86,8 @@ public final class BatteryBackupHelperTest { private static final int UID1 = 1; private Context mContext; private PrintWriter mPrintWriter; private StringWriter mStringWriter; private BatteryBackupHelper mBatteryBackupHelper; @Mock Loading @@ -109,6 +113,8 @@ public final class BatteryBackupHelperTest { 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); Loading @@ -126,6 +132,7 @@ public final class BatteryBackupHelperTest { @After public void resetShadows() { ShadowUserHandle.reset(); BatteryBackupHelper.getSharedPreferences(mContext).edit().clear().apply(); } @Test Loading Loading @@ -216,6 +223,8 @@ public final class BatteryBackupHelperTest { // 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 Loading @@ -232,6 +241,7 @@ public final class BatteryBackupHelperTest { // "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 Loading @@ -248,6 +258,7 @@ public final class BatteryBackupHelperTest { // "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 Loading Loading @@ -357,6 +368,11 @@ public final class BatteryBackupHelperTest { 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); Loading
tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public final class BatteryHistoricalLogUtilTest { @Test public void printHistoricalLog_withDefaultLogs() { BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); assertThat(mTestStringWriter.toString()).contains("No past logs"); assertThat(mTestStringWriter.toString()).contains("nothing to dump"); } @Test Loading @@ -58,7 +58,7 @@ public final class BatteryHistoricalLogUtilTest { BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); assertThat(mTestStringWriter.toString()).contains( "pkg1\tAction:APPLY\tEvent:logs\tTimestamp:"); "pkg1\taction:APPLY\tevent:logs"); } @Test Loading