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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user