diff options
4 files changed, 171 insertions, 15 deletions
diff --git a/core/java/android/app/backup/BackupRestoreEventLogger.java b/core/java/android/app/backup/BackupRestoreEventLogger.java index 112c5fd808ef..8bde3a5f2efa 100644 --- a/core/java/android/app/backup/BackupRestoreEventLogger.java +++ b/core/java/android/app/backup/BackupRestoreEventLogger.java @@ -34,9 +34,11 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Class to log B&R stats for each data type that is backed up and restored by the calling app. @@ -325,6 +327,21 @@ public final class BackupRestoreEventLogger { } } + /** @hide */ + public static String toString(DataTypeResult result) { + Objects.requireNonNull(result, "result cannot be null"); + StringBuilder string = new StringBuilder("type=").append(result.mDataType) + .append(", successCount=").append(result.mSuccessCount) + .append(", failCount=").append(result.mFailCount); + if (!result.mErrors.isEmpty()) { + string.append(", errors=").append(result.mErrors); + } + if (result.mMetadataHash != null) { + string.append(", metadataHash=").append(Arrays.toString(result.mMetadataHash)); + } + return string.toString(); + } + /** * Encapsulate logging results for a single data type. */ diff --git a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java index 7b41217d6200..ab2e77e57b47 100644 --- a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java +++ b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java @@ -23,6 +23,8 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertThrows; + import android.app.backup.BackupRestoreEventLogger.DataTypeResult; import android.os.Parcel; import android.platform.test.annotations.Presubmit; @@ -32,6 +34,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.server.backup.Flags; +import com.google.common.truth.Expect; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -42,6 +46,7 @@ import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Optional; @Presubmit @@ -64,6 +69,9 @@ public class BackupRestoreEventLoggerTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public final Expect expect = Expect.create(); + @Before public void setUp() throws Exception { mHashDigest = MessageDigest.getInstance("SHA-256"); @@ -366,6 +374,32 @@ public class BackupRestoreEventLoggerTest { assertThat(mLogger.getLoggingResults()).isEmpty(); } + @Test + public void testDataTypeResultToString_nullArgs() { + assertThrows(NullPointerException.class, () -> BackupRestoreEventLogger.toString(null)); + } + + @Test + public void testDataTypeResultToString_typeOnly() { + DataTypeResult result = new DataTypeResult("The Type is Bond, James Bond!"); + + expect.withMessage("toString()") + .that(BackupRestoreEventLogger.toString(result)).isEqualTo( + "type=The Type is Bond, James Bond!, successCount=0, failCount=0"); + } + + @Test + public void testDataTypeResultToString_allFields() { + DataTypeResult result = DataTypeResultTest.createDataTypeResult( + "The Type is Bond, James Bond!", /* successCount= */ 42, /* failCount= */ 108, + Map.of("D'OH!", 666, "", 0), new byte[] { 4, 8, 15, 16, 23, 42 }); + + expect.withMessage("toString()") + .that(BackupRestoreEventLogger.toString(result)).isEqualTo( + "type=The Type is Bond, James Bond!, successCount=42, failCount=108, " + + "errors={=0, D'OH!=666}, metadataHash=[4, 8, 15, 16, 23, 42]"); + } + private static DataTypeResult getResultForDataType( BackupRestoreEventLogger logger, String dataType) { Optional<DataTypeResult> result = getResultForDataTypeIfPresent(logger, dataType); diff --git a/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java new file mode 100644 index 000000000000..cf9e9c6e2f95 --- /dev/null +++ b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.app.backup; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.app.backup.BackupRestoreEventLogger.DataTypeResult; +import android.os.Bundle; +import android.os.Parcel; + +import com.google.common.truth.Expect; + +import org.junit.Rule; +import org.junit.Test; + +import java.util.Map; + +public final class DataTypeResultTest { + + @Rule + public final Expect expect = Expect.create(); + + @Test + public void testGetters_defaultConstructorFields() { + var result = new DataTypeResult("The Type is Bond, James Bond!"); + + expect.withMessage("getDataType()").that(result.getDataType()) + .isEqualTo("The Type is Bond, James Bond!"); + expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(0); + expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(0); + expect.withMessage("getErrorsCount()").that(result.getErrors()).isEmpty(); + expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).isNull(); + expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0); + } + + @Test + public void testGetters_allFields() { + DataTypeResult result = createDataTypeResult("The Type is Bond, James Bond!", + /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666), + new byte[] { 4, 8, 15, 16, 23, 42 }); + + expect.withMessage("getDataType()").that(result.getDataType()) + .isEqualTo("The Type is Bond, James Bond!"); + expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(42); + expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(108); + expect.withMessage("getErrorsCount()").that(result.getErrors()).containsExactly("D'OH!", + 666); + expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).asList() + .containsExactly((byte) 4, (byte) 8, (byte) 15, (byte) 16, (byte) 23, (byte) 42) + .inOrder(); + expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0); + } + + @Test + public void testParcelMethods() { + DataTypeResult original = createDataTypeResult("The Type is Bond, James Bond!", + /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666), + new byte[] { 4, 8, 15, 16, 23, 42 }); + Parcel parcel = Parcel.obtain(); + try { + original.writeToParcel(parcel, /* flags= */ 0); + + parcel.setDataPosition(0); + var clone = DataTypeResult.CREATOR.createFromParcel(parcel); + assertWithMessage("createFromParcel()").that(clone).isNotNull(); + + expect.withMessage("getDataType()").that(clone.getDataType()) + .isEqualTo(original.getDataType()); + expect.withMessage("getSuccessCount()").that(clone.getSuccessCount()) + .isEqualTo(original.getSuccessCount()); + expect.withMessage("getFailCount()").that(clone.getFailCount()) + .isEqualTo(original.getFailCount()); + expect.withMessage("getErrorsCount()").that(clone.getErrors()) + .containsExactlyEntriesIn(original.getErrors()).inOrder(); + expect.withMessage("getMetadataHash()").that(clone.getMetadataHash()) + .isEqualTo(original.getMetadataHash()); + expect.withMessage("describeContents()").that(clone.describeContents()).isEqualTo(0); + } finally { + parcel.recycle(); + } + } + + static DataTypeResult createDataTypeResult(String dataType, int successCount, int failCount, + Map<String, Integer> errors, byte... metadataHash) { + Parcel parcel = Parcel.obtain(); + try { + parcel.writeString(dataType); + parcel.writeInt(successCount); + parcel.writeInt(failCount); + Bundle errorsBundle = new Bundle(); + errors.entrySet() + .forEach(entry -> errorsBundle.putInt(entry.getKey(), entry.getValue())); + parcel.writeBundle(errorsBundle); + parcel.writeByteArray(metadataHash); + + parcel.setDataPosition(0); + var result = DataTypeResult.CREATOR.createFromParcel(parcel); + assertWithMessage("createFromParcel()").that(result).isNotNull(); + return result; + } finally { + parcel.recycle(); + } + } +} diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java index a3b06e8c71fc..1af3bc898306 100644 --- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java @@ -23,6 +23,7 @@ import android.app.backup.BackupAnnotations; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupManagerMonitor; +import android.app.backup.BackupRestoreEventLogger; import android.app.backup.BackupRestoreEventLogger.DataTypeResult; import android.app.backup.BackupTransport; import android.app.backup.RestoreDescription; @@ -52,7 +53,6 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -924,21 +924,9 @@ public class LocalTransport extends BackupTransport { BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS, DataTypeResult.class); for (DataTypeResult result : results) { - Log.i(TAG, "\tdataType: " + result.getDataType()); - Log.i(TAG, "\tsuccessCount: " + result.getSuccessCount()); - Log.i(TAG, "\tfailCount: " + result.getFailCount()); - Log.i(TAG, "\tmetadataHash: " + Arrays.toString(result.getMetadataHash())); - - if (!result.getErrors().isEmpty()) { - Log.i(TAG, "\terrors {"); - for (String error : result.getErrors().keySet()) { - Log.i(TAG, "\t\t" + error + ": " + result.getErrors().get(error)); - } - Log.i(TAG, "\t}"); - } - - Log.i(TAG, "}"); + Log.i(TAG, "\t" + BackupRestoreEventLogger.toString(result)); } + Log.i(TAG, "}"); } } } |