Merge "Add device build information in the backup stage" into udc-dev am: 1d818600a4

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

Change-Id: I3c91272947fa868bb2ae858115bf0af6440b2b97
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
index eb4bbf6..5d4f266 100644
--- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
@@ -25,6 +25,7 @@
 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 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 @@
     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<ApplicationInfo> mTestApplicationInfoList = null;
@@ -83,9 +92,21 @@
             return;
         }
         final List<String> 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 @@
 
     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 @@
         } 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 9f30473..724ca04 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -166,4 +166,14 @@
      * Returns {@link Set} for ignoring task root class names for screen on time
      */
     Set<String> 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 d65c212..f73a4d5 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -188,4 +188,14 @@
     public Set<String> 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 a800fdb..49354c1 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.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.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 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 @@
     private PrintWriter mPrintWriter;
     private StringWriter mStringWriter;
     private BatteryBackupHelper mBatteryBackupHelper;
+    private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
 
     @Mock
     private PackageManager mPackageManager;
@@ -112,6 +116,8 @@
     @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 @@
     }
 
     @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 @@
                 .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 @@
                 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.