diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java index eb4bbf687d7..5d4f2664050 100644 --- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java +++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.os.Build; import android.os.IDeviceIdleController; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -36,6 +37,7 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; +import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.fuelgauge.PowerAllowlistBackend; import java.io.IOException; @@ -56,6 +58,13 @@ public final class BatteryBackupHelper implements BackupHelper { static final String DELIMITER = ","; static final String DELIMITER_MODE = ":"; static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list"; + static final String KEY_BUILD_BRAND = "device_build_brand"; + static final String KEY_BUILD_PRODUCT = "device_build_product"; + static final String KEY_BUILD_MANUFACTURER = "device_build_manufacture"; + static final String KEY_BUILD_FINGERPRINT = "device_build_fingerprint"; + // Customized fields for device extra information. + static final String KEY_BUILD_METADATA_1 = "device_build_metadata_1"; + static final String KEY_BUILD_METADATA_2 = "device_build_metadata_2"; @VisibleForTesting ArraySet mTestApplicationInfoList = null; @@ -83,9 +92,21 @@ public final class BatteryBackupHelper implements BackupHelper { return; } final List allowlistedApps = getFullPowerList(); - if (allowlistedApps != null) { - backupOptimizationMode(data, allowlistedApps); + if (allowlistedApps == null) { + return; } + + writeBackupData(data, KEY_BUILD_BRAND, Build.BRAND); + writeBackupData(data, KEY_BUILD_PRODUCT, Build.PRODUCT); + writeBackupData(data, KEY_BUILD_MANUFACTURER, Build.MANUFACTURER); + writeBackupData(data, KEY_BUILD_FINGERPRINT, Build.FINGERPRINT); + // Add customized device build metadata fields. + PowerUsageFeatureProvider provider = FeatureFactory.getFactory(mContext) + .getPowerUsageFeatureProvider(mContext); + writeBackupData(data, KEY_BUILD_METADATA_1, provider.getBuildMetadata1(mContext)); + writeBackupData(data, KEY_BUILD_METADATA_2, provider.getBuildMetadata2(mContext)); + + backupOptimizationMode(data, allowlistedApps); } @Override @@ -301,6 +322,9 @@ public final class BatteryBackupHelper implements BackupHelper { private static void writeBackupData( BackupDataOutput data, String dataKey, String dataContent) { + if (dataContent == null || dataContent.isEmpty()) { + return; + } final byte[] dataContentBytes = dataContent.getBytes(); try { data.writeEntityHeader(dataKey, dataContentBytes.length); @@ -308,5 +332,6 @@ public final class BatteryBackupHelper implements BackupHelper { } catch (IOException e) { Log.e(TAG, "writeBackupData() is failed for " + dataKey, e); } + Log.d(TAG, String.format("%s:%s", dataKey, dataContent)); } } diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 9f30473e209..724ca04d7ae 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -166,4 +166,14 @@ public interface PowerUsageFeatureProvider { * Returns {@link Set} for ignoring task root class names for screen on time */ Set getIgnoreScreenOnTimeTaskRootSet(); + + /** + * Returns the customized device build information for data backup + */ + String getBuildMetadata1(Context context); + + /** + * Returns the customized device build information for data backup + */ + String getBuildMetadata2(Context context); } diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index d65c2126658..f73a4d5a256 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -188,4 +188,14 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider public Set getIgnoreScreenOnTimeTaskRootSet() { return new ArraySet<>(); } + + @Override + public String getBuildMetadata1(Context context) { + return null; + } + + @Override + public String getBuildMetadata2(Context context) { + return null; + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java index a800fdbd2cc..49354c1c5b5 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java @@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; @@ -45,6 +46,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; +import android.os.Build; import android.os.IDeviceIdleController; import android.os.RemoteException; import android.os.UserHandle; @@ -53,6 +55,7 @@ import android.util.ArraySet; import com.android.settings.TestUtils; import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; +import com.android.settings.testutils.FakeFeatureFactory; import com.android.settingslib.fuelgauge.PowerAllowlistBackend; import org.junit.After; @@ -89,6 +92,7 @@ public final class BatteryBackupHelperTest { private PrintWriter mPrintWriter; private StringWriter mStringWriter; private BatteryBackupHelper mBatteryBackupHelper; + private PowerUsageFeatureProvider mPowerUsageFeatureProvider; @Mock private PackageManager mPackageManager; @@ -112,6 +116,8 @@ public final class BatteryBackupHelperTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mPowerUsageFeatureProvider = + FakeFeatureFactory.setupForTest().powerUsageFeatureProvider; mContext = spy(RuntimeEnvironment.application); mStringWriter = new StringWriter(); mPrintWriter = new PrintWriter(mStringWriter); @@ -136,19 +142,11 @@ public final class BatteryBackupHelperTest { } @Test - public void performBackup_nullPowerList_notBackupPowerList() throws Exception { - doReturn(null).when(mDeviceController).getFullPowerWhitelist(); - mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null); - - verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt()); - } - - @Test - public void performBackup_emptyPowerList_notBackupPowerList() throws Exception { + public void performBackup_emptyPowerList_backupPowerList() throws Exception { doReturn(new String[0]).when(mDeviceController).getFullPowerWhitelist(); mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null); - verify(mBackupDataOutput, never()).writeEntityHeader(anyString(), anyInt()); + verify(mBackupDataOutput, atLeastOnce()).writeEntityHeader(anyString(), anyInt()); } @Test @@ -330,6 +328,26 @@ public final class BatteryBackupHelperTest { .setAppUsageState(MODE_RESTRICTED, Action.RESTORE); } + @Test + public void performBackup_backupDeviceBuildInformation() throws Exception { + final String[] fullPowerList = {"com.android.package"}; + doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist(); + doReturn(null).when(mPowerUsageFeatureProvider).getBuildMetadata1(mContext); + final String deviceMetadata = "device.metadata.test_device"; + doReturn(deviceMetadata).when(mPowerUsageFeatureProvider).getBuildMetadata2(mContext); + + mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null); + + final InOrder inOrder = inOrder(mBackupDataOutput); + verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_BRAND, Build.BRAND); + verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_PRODUCT, Build.PRODUCT); + verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_MANUFACTURER, Build.MANUFACTURER); + verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_FINGERPRINT, Build.FINGERPRINT); + inOrder.verify(mBackupDataOutput, never()).writeEntityHeader( + eq(BatteryBackupHelper.KEY_BUILD_METADATA_1), anyInt()); + verifyBackupData(inOrder, BatteryBackupHelper.KEY_BUILD_METADATA_2, deviceMetadata); + } + private void mockUid(int uid, String packageName) throws Exception { doReturn(uid).when(mPackageManager) .getPackageUid(packageName, PackageManager.GET_META_DATA); @@ -401,6 +419,13 @@ public final class BatteryBackupHelperTest { new ArraySet<>(Arrays.asList(applicationInfo1, applicationInfo2, applicationInfo3)); } + private void verifyBackupData( + InOrder inOrder, String dataKey, String dataContent) throws Exception { + final byte[] expectedBytes = dataContent.getBytes(); + inOrder.verify(mBackupDataOutput).writeEntityHeader(dataKey, expectedBytes.length); + inOrder.verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length); + } + @Implements(UserHandle.class) public static class ShadowUserHandle { // Sets the default as thte OWNER role.