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

Commit 9cc61d58 authored by Ruslan Tkhakokhov's avatar Ruslan Tkhakokhov
Browse files

[FSD2D] Pass @OperationType at agent creation in B&R code

Bug: 160407842
Test: atest UserBackupManagerServiceTest BackupAgentTest
        KeyValueBackupTaskTest BackupEligibilityRulesTest
        PerformUnifiedRestoreTaskTest
Change-Id: Ic0747cfe48ad5b5f2f3166c1e96a4aa45367234d
parent 6cf1da7d
Loading
Loading
Loading
Loading
+93 −9
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.app.backup;
import android.annotation.Nullable;
import android.app.IBackupAgent;
import android.app.QueuedWork;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
import android.content.Context;
import android.content.ContextWrapper;
@@ -38,6 +39,8 @@ import android.system.StructStat;
import android.util.ArraySet;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

import libcore.io.IoUtils;

import org.xmlpull.v1.XmlPullParserException;
@@ -50,6 +53,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

@@ -129,6 +133,7 @@ import java.util.concurrent.CountDownLatch;
public abstract class BackupAgent extends ContextWrapper {
    private static final String TAG = "BackupAgent";
    private static final boolean DEBUG = false;
    private static final int DEFAULT_OPERATION_TYPE = OperationType.BACKUP;

    /** @hide */
    public static final int RESULT_SUCCESS = 0;
@@ -186,6 +191,9 @@ public abstract class BackupAgent extends ContextWrapper {
    Handler mHandler = null;

    @Nullable private UserHandle mUser;
     // This field is written from the main thread (in onCreate), and read in a Binder thread (in
     // onFullBackup that is called from system_server via Binder).
    @OperationType private volatile int mOperationType = DEFAULT_OPERATION_TYPE;

    Handler getHandler() {
        if (mHandler == null) {
@@ -228,6 +236,13 @@ public abstract class BackupAgent extends ContextWrapper {
    public void onCreate() {
    }

    /**
     * @hide
     */
    public void onCreate(UserHandle user) {
        onCreate(user, DEFAULT_OPERATION_TYPE);
    }

    /**
     * Provided as a convenience for agent implementations that need an opportunity
     * to do one-time initialization before the actual backup or restore operation
@@ -236,10 +251,11 @@ public abstract class BackupAgent extends ContextWrapper {
     *
     * @hide
     */
    public void onCreate(UserHandle user) {
    public void onCreate(UserHandle user, @OperationType int operationType) {
        onCreate();

        mUser = user;
        mOperationType = operationType;
    }

    /**
@@ -390,12 +406,9 @@ public abstract class BackupAgent extends ContextWrapper {
            return;
        }

        Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap;
        ArraySet<PathWithRequiredFlags> manifestExcludeSet;
        IncludeExcludeRules includeExcludeRules;
        try {
            manifestIncludeMap =
                    backupScheme.maybeParseAndGetCanonicalIncludePaths();
            manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths();
            includeExcludeRules = getIncludeExcludeRules(backupScheme);
        } catch (IOException | XmlPullParserException e) {
            if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
                Log.v(FullBackup.TAG_XML_PARSER,
@@ -404,6 +417,10 @@ public abstract class BackupAgent extends ContextWrapper {
            }
            return;
        }
        Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap
                = includeExcludeRules.getIncludeMap();
        Set<PathWithRequiredFlags> manifestExcludeSet
                = includeExcludeRules.getExcludeSet();

        final String packageName = getPackageName();
        final ApplicationInfo appInfo = getApplicationInfo();
@@ -528,6 +545,24 @@ public abstract class BackupAgent extends ContextWrapper {
        }
    }

    /** @hide */
    @VisibleForTesting
    public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme)
            throws IOException, XmlPullParserException {
        if (mOperationType == OperationType.MIGRATION) {
            return IncludeExcludeRules.emptyRules();
        }

        Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap;
        ArraySet<PathWithRequiredFlags> manifestExcludeSet;

        manifestIncludeMap =
                backupScheme.maybeParseAndGetCanonicalIncludePaths();
        manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths();

        return new IncludeExcludeRules(manifestIncludeMap, manifestExcludeSet);
    }

    /**
     * Notification that the application's current backup operation causes it to exceed
     * the maximum size permitted by the transport.  The ongoing backup operation is
@@ -570,7 +605,7 @@ public abstract class BackupAgent extends ContextWrapper {
     */
    private void applyXmlFiltersAndDoFullBackupForDomain(String packageName, String domainToken,
            Map<String, Set<PathWithRequiredFlags>> includeMap,
            ArraySet<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet,
            Set<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet,
            FullBackupDataOutput data) throws IOException {
        if (includeMap == null || includeMap.size() == 0) {
            // Do entire sub-tree for the provided token.
@@ -742,7 +777,7 @@ public abstract class BackupAgent extends ContextWrapper {
     * @hide
     */
    protected final void fullBackupFileTree(String packageName, String domain, String startingPath,
                                            ArraySet<PathWithRequiredFlags> manifestExcludes,
                                            Set<PathWithRequiredFlags> manifestExcludes,
                                            ArraySet<String> systemExcludes,
            FullBackupDataOutput output) {
        // Pull out the domain and set it aside to use when making the tarball.
@@ -811,7 +846,7 @@ public abstract class BackupAgent extends ContextWrapper {
    }

    private boolean manifestExcludesContainFilePath(
        ArraySet<PathWithRequiredFlags> manifestExcludes, String filePath) {
        Set<PathWithRequiredFlags> manifestExcludes, String filePath) {
        for (PathWithRequiredFlags exclude : manifestExcludes) {
            String excludePath = exclude.getPath();
            if (excludePath != null && excludePath.equals(filePath)) {
@@ -1265,4 +1300,53 @@ public abstract class BackupAgent extends ContextWrapper {
            throw new IllegalStateException(mMessage);
        }
    }

    /**  @hide */
    @VisibleForTesting
    public static class IncludeExcludeRules {
        private final Map<String, Set<PathWithRequiredFlags>> mManifestIncludeMap;
        private final Set<PathWithRequiredFlags> mManifestExcludeSet;

        /** @hide */
        public IncludeExcludeRules(
                Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap,
                Set<PathWithRequiredFlags> manifestExcludeSet) {
            mManifestIncludeMap = manifestIncludeMap;
            mManifestExcludeSet = manifestExcludeSet;
        }

        /**  @hide */
        @VisibleForTesting
        public static IncludeExcludeRules emptyRules() {
            return new IncludeExcludeRules(Collections.emptyMap(), new ArraySet<>());
        }

        private Map<String, Set<PathWithRequiredFlags>> getIncludeMap() {
            return mManifestIncludeMap;
        }

        private Set<PathWithRequiredFlags> getExcludeSet() {
            return mManifestExcludeSet;
        }

        /**  @hide */
        @Override
        public int hashCode() {
            return Objects.hash(mManifestIncludeMap, mManifestExcludeSet);
        }

        /**  @hide */
        @Override
        public boolean equals(Object object) {
            if (this == object) {
                return true;
            }
            if (object == null || getClass() != object.getClass()) {
                return false;
            }
            IncludeExcludeRules that = (IncludeExcludeRules) object;
            return Objects.equals(mManifestIncludeMap, that.mManifestIncludeMap) &&
                    Objects.equals(mManifestExcludeSet, that.mManifestExcludeSet);
        }
    }
}
+104 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.mockito.Mockito.when;

import android.app.backup.BackupAgent.IncludeExcludeRules;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;

import androidx.test.runner.AndroidJUnit4;

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

import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

@Presubmit
@RunWith(AndroidJUnit4.class)
public class BackupAgentTest {
    // An arbitrary user.
    private static final UserHandle USER_HANDLE = new UserHandle(15);

    @Mock FullBackup.BackupScheme mBackupScheme;

    private BackupAgent mBackupAgent;

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

    @Test
    public void testGetIncludeExcludeRules_isMigration_returnsEmptyRules()  throws Exception {
        mBackupAgent = getAgentForOperationType(OperationType.MIGRATION);

        IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme);
        assertThat(rules).isEqualTo(IncludeExcludeRules.emptyRules());
    }

    @Test
    public void testGetIncludeExcludeRules_isNotMigration_returnsRules() throws Exception {
        PathWithRequiredFlags path = new PathWithRequiredFlags("path", /* requiredFlags */ 0);
        Map<String, Set<PathWithRequiredFlags>> includePaths = Collections.singletonMap("test",
                Collections.singleton(path));
        ArraySet<PathWithRequiredFlags> excludePaths = new ArraySet<>();
        excludePaths.add(path);
        IncludeExcludeRules expectedRules = new IncludeExcludeRules(includePaths, excludePaths);

        mBackupAgent = getAgentForOperationType(OperationType.BACKUP);
        when(mBackupScheme.maybeParseAndGetCanonicalExcludePaths()).thenReturn(excludePaths);
        when(mBackupScheme.maybeParseAndGetCanonicalIncludePaths()).thenReturn(includePaths);

        IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme);
        assertThat(rules).isEqualTo(expectedRules);
    }

    private BackupAgent getAgentForOperationType(@OperationType int operationType) {
        BackupAgent agent = new TestFullBackupAgent();
        agent.onCreate(USER_HANDLE, operationType);
        return agent;
    }

    private static class TestFullBackupAgent extends BackupAgent {

        @Override
        public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
                ParcelFileDescriptor newState) throws IOException {
            // Left empty as this is a full backup agent.
        }

        @Override
        public void onRestore(BackupDataInput data, int appVersionCode,
                ParcelFileDescriptor newState) throws IOException {
            // Left empty as this is a full backup agent.
        }
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_

import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupManager;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
import android.app.backup.IBackupCallback;
@@ -146,7 +147,8 @@ public class KeyValueAdbBackupEngine {
    private IBackupAgent bindToAgent(ApplicationInfo targetApp) {
        try {
            return mBackupManagerService.bindToAgentSynchronous(targetApp,
                    ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL);
                    ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL,
                    BackupManager.OperationType.BACKUP);
        } catch (SecurityException e) {
            Slog.e(TAG, "error in binding to agent for package " + targetApp.packageName
                    + ". " + e);
+4 −2
Original line number Diff line number Diff line
@@ -1643,13 +1643,15 @@ public class UserBackupManagerService {

    /** Fires off a backup agent, blocking until it attaches or times out. */
    @Nullable
    public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
    public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
            @OperationType int operationType) {
        IBackupAgent agent = null;
        synchronized (mAgentConnectLock) {
            mConnecting = true;
            mConnectedAgent = null;
            try {
                if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId)) {
                if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
                        operationType)) {
                    Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app));

                    // success; wait for the agent to arrive
+7 −2
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import com.android.server.backup.BackupAgentTimeoutParameters;
import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.remote.RemoteCall;
import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.FullBackupUtils;

import java.io.File;
@@ -64,6 +65,7 @@ public class FullBackupEngine {
    private final int mOpToken;
    private final int mTransportFlags;
    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
    private final BackupEligibilityRules mBackupEligibilityRules;

    class FullBackupRunner implements Runnable {
        private final @UserIdInt int mUserId;
@@ -190,7 +192,8 @@ public class FullBackupEngine {
            BackupRestoreTask timeoutMonitor,
            long quota,
            int opToken,
            int transportFlags) {
            int transportFlags,
            BackupEligibilityRules backupEligibilityRules) {
        this.backupManagerService = backupManagerService;
        mOutput = output;
        mPreflightHook = preflightHook;
@@ -204,6 +207,7 @@ public class FullBackupEngine {
                Objects.requireNonNull(
                        backupManagerService.getAgentTimeoutParameters(),
                        "Timeout parameters cannot be null");
        mBackupEligibilityRules = backupEligibilityRules;
    }

    public int preflightCheck() throws RemoteException {
@@ -302,7 +306,8 @@ public class FullBackupEngine {
            }
            mAgent =
                    backupManagerService.bindToAgentSynchronous(
                            mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL);
                            mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL,
                            mBackupEligibilityRules.getOperationType());
        }
        return mAgent != null;
    }
Loading