Merge "Record app optimization mode backup into BatteryHistoricalLog" into udc-dev am: 1b91f61633

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/23124522

Change-Id: Ia53318c8bf1dcd32af55934506a2ea0d15250e86
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2023-05-11 11:33:42 +00:00
committed by Automerger Merge Worker
5 changed files with 73 additions and 33 deletions

View File

@@ -19,10 +19,11 @@ message BatteryOptimizeHistoricalLogEntry {
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;
}
}

View File

@@ -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;
@@ -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;
@@ -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 = ":";
@@ -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);
@@ -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++;
}
@@ -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);

View File

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

View File

@@ -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;
@@ -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
@@ -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);
@@ -126,6 +132,7 @@ public final class BatteryBackupHelperTest {
@After
public void resetShadows() {
ShadowUserHandle.reset();
BatteryBackupHelper.getSharedPreferences(mContext).edit().clear().apply();
}
@Test
@@ -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
@@ -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
@@ -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
@@ -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);

View File

@@ -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
@@ -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