Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ecc97c0b authored by Ruslan Tkhakokhov's avatar Ruslan Tkhakokhov
Browse files

Make BackupRestoreEventLogger System API

Also adds BackupManager#getBackupRestoreEventLogger() - a method to
instantiate BackupRestoreEventLogger.

Bug: 244436184
Test: atest FrameworksCoreTests:BackupManagerTest
Change-Id: I5539094dc2c465013c9567fd35313dc595218571
parent f86b874c
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -1474,6 +1474,7 @@ package android.app.backup {
    method @RequiresPermission(android.Manifest.permission.BACKUP) public void cancelBackups();
    method @RequiresPermission(android.Manifest.permission.BACKUP) public void excludeKeysFromRestore(@NonNull String, @NonNull java.util.List<java.lang.String>);
    method @RequiresPermission(android.Manifest.permission.BACKUP) public long getAvailableRestoreToken(String);
    method @NonNull public android.app.backup.BackupRestoreEventLogger getBackupRestoreEventLogger(@NonNull android.app.backup.BackupAgent);
    method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String);
    method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
    method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.ComponentName getCurrentTransportComponent();
@@ -1592,6 +1593,33 @@ package android.app.backup {
    field public final long bytesTransferred;
  }
  public class BackupRestoreEventLogger {
    method public void logBackupMetaData(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, @NonNull String);
    method public void logItemsBackedUp(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int);
    method public void logItemsBackupFailed(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int, @android.app.backup.BackupRestoreEventLogger.BackupRestoreError @Nullable String);
    method public void logItemsRestoreFailed(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int, @android.app.backup.BackupRestoreEventLogger.BackupRestoreError @Nullable String);
    method public void logItemsRestored(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int);
    method public void logRestoreMetadata(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, @NonNull String);
  }
  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface BackupRestoreEventLogger.BackupRestoreDataType {
  }
  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface BackupRestoreEventLogger.BackupRestoreError {
  }
  public static final class BackupRestoreEventLogger.DataTypeResult implements android.os.Parcelable {
    ctor public BackupRestoreEventLogger.DataTypeResult(@NonNull String);
    method public int describeContents();
    method @android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull public String getDataType();
    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getErrors();
    method public int getFailCount();
    method @Nullable public byte[] getMetadataHash();
    method public int getSuccessCount();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.app.backup.BackupRestoreEventLogger.DataTypeResult> CREATOR;
  }
  public class BackupTransport {
    ctor public BackupTransport();
    method public int abortFullRestore();
+23 −0
Original line number Diff line number Diff line
@@ -1018,6 +1018,29 @@ public class BackupManager {
        }
    }

    /**
     * Get an instance of {@link BackupRestoreEventLogger} to report B&R related events during an
     * ongoing backup or restore operation.
     *
     * @param backupAgent the agent currently running a B&R operation.
     *
     * @return an instance of {@code BackupRestoreEventLogger} or {@code null} if the agent has not
     *         finished initialisation, i.e. {@link BackupAgent#onCreate()} has not been called yet.
     * @throws IllegalStateException if called before the agent has finished initialisation.
     *
     * @hide
     */
    @NonNull
    @SystemApi
    public BackupRestoreEventLogger getBackupRestoreEventLogger(@NonNull BackupAgent backupAgent) {
        BackupRestoreEventLogger logger = backupAgent.getBackupRestoreEventLogger();
        if (logger == null) {
            throw new IllegalStateException("Attempting to get logger on an uninitialised "
                    + "BackupAgent");
        }
        return backupAgent.getBackupRestoreEventLogger();
    }

    /*
     * We wrap incoming binder calls with a private class implementation that
     * redirects them into main-thread actions.  This serializes the backup
+8 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.app.backup;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,7 +36,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;

// TODO(b/244436184): Make this @SystemApi
/**
 * Class to log B&R stats for each data type that is backed up and restored by the calling app.
 *
@@ -46,12 +46,15 @@ import java.util.Map;
 *
 * @hide
 */
@SystemApi
public class BackupRestoreEventLogger {
    private static final String TAG = "BackupRestoreEventLogger";

    /**
     * Max number of unique data types for which an instance of this logger can store info. Attempts
     * to use more distinct data type values will be rejected.
     *
     * @hide
     */
    public static final int DATA_TYPES_ALLOWED = 15;

@@ -301,7 +304,7 @@ public class BackupRestoreEventLogger {
    /**
     * Encapsulate logging results for a single data type.
     */
    public static class DataTypeResult implements Parcelable {
    public static final class DataTypeResult implements Parcelable {
        @BackupRestoreDataType
        private final String mDataType;
        private int mSuccessCount;
@@ -309,7 +312,7 @@ public class BackupRestoreEventLogger {
        private final Map<String, Integer> mErrors = new HashMap<>();
        private byte[] mMetadataHash;

        public DataTypeResult(String dataType) {
        public DataTypeResult(@NonNull String dataType) {
            mDataType = dataType;
        }

@@ -358,7 +361,7 @@ public class BackupRestoreEventLogger {
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeString(mDataType);

            dest.writeInt(mSuccessCount);
@@ -374,6 +377,7 @@ public class BackupRestoreEventLogger {
            dest.writeByteArray(mMetadataHash);
        }

        @NonNull
        public static final Parcelable.Creator<DataTypeResult> CREATOR =
                new Parcelable.Creator<>() {
                    public DataTypeResult createFromParcel(Parcel in) {
+102 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.assertThat;

import static org.junit.Assert.assertThrows;

import android.app.backup.BackupAnnotations.BackupDestination;
import android.app.backup.BackupAnnotations.OperationType;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;

import androidx.test.runner.AndroidJUnit4;

import org.junit.Before;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.io.IOException;

@Presubmit
@RunWith(AndroidJUnit4.class)
public class BackupManagerTest {
    private BackupManager mBackupManager;

    @Mock
    Context mContext;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        mBackupManager = new BackupManager(mContext);
    }

    @Test
    public void testGetBackupRestoreEventLogger_returnsBackupLoggerForBackup() {
        BackupAgent agent = getTestAgent();
        agent.onCreate(UserHandle.SYSTEM, BackupDestination.CLOUD,
                OperationType.BACKUP);

        BackupRestoreEventLogger logger = mBackupManager.getBackupRestoreEventLogger(agent);

        assertThat(logger.getOperationType()).isEqualTo(OperationType.BACKUP);
    }

    @Test
    public void testGetBackupRestoreEventLogger_returnsRestoreLoggerForRestore() {
        BackupAgent agent = getTestAgent();
        agent.onCreate(UserHandle.SYSTEM, BackupDestination.CLOUD,
                OperationType.RESTORE);

        BackupRestoreEventLogger logger = mBackupManager.getBackupRestoreEventLogger(agent);

        assertThat(logger.getOperationType()).isEqualTo(OperationType.RESTORE);
    }

    @Test
    public void testGetBackupRestoreEventLogger_uninitialisedAgent_throwsException() {
        BackupAgent agent = getTestAgent();

        assertThrows(IllegalStateException.class,
                () -> mBackupManager.getBackupRestoreEventLogger(agent));
    }

    private static BackupAgent getTestAgent() {
        return new BackupAgent() {
            @Override
            public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
                    ParcelFileDescriptor newState) throws IOException {

            }

            @Override
            public void onRestore(BackupDataInput data, int appVersionCode,
                    ParcelFileDescriptor newState) throws IOException {

            }
        };
    }

}