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

Commit c1b6ca05 authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

Increase PerformBackupTask unit coverage

With KV Refactor in mind.
* Added tests around empty queue and single package backups.
* Refactored a bit some of the existing tests.
* Moved from mocking BMS to using a real instance and had to adjust a
  few things for this.

Test: atest PerformBackupTaskTest
Change-Id: I0ee3be32c7cbac5ed2cdc2717408749907c15ade
parent acda839b
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IBackupAgent;
import android.app.PendingIntent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupManager;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.FullBackup;
@@ -704,7 +705,7 @@ public class BackupManagerService implements BackupManagerServiceInterface {
     * process-local non-lifecycle agent instance, so we manually set up the context
     * topology for it.
     */
    public PackageManagerBackupAgent makeMetadataAgent() {
    public BackupAgent makeMetadataAgent() {
        PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager);
        pmAgent.attach(mContext);
        pmAgent.onCreate();
@@ -784,7 +785,7 @@ public class BackupManagerService implements BackupManagerServiceInterface {
    }

    @VisibleForTesting
    BackupManagerService(
    public BackupManagerService(
            Context context,
            Trampoline parent,
            HandlerThread backupThread,
@@ -1749,6 +1750,16 @@ public class BackupManagerService implements BackupManagerServiceInterface {
        }
    }

    public void putOperation(int token, Operation operation) {
        if (MORE_DEBUG) {
            Slog.d(TAG, "Adding operation token=" + Integer.toHexString(token) + ", operation type="
                    + operation.type);
        }
        synchronized (mCurrentOpLock) {
            mCurrentOperations.put(token, operation);
        }
    }

    public void removeOperation(int token) {
        if (MORE_DEBUG) {
            Slog.d(TAG, "Removing operation token=" + Integer.toHexString(token));
+4 −5
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTOR
import android.annotation.Nullable;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupManager;
@@ -205,11 +206,9 @@ public class PerformBackupTask implements BackupRestoreTask {
     * Put this task in the repository of running tasks.
     */
    private void registerTask() {
        synchronized (backupManagerService.getCurrentOpLock()) {
            backupManagerService.getCurrentOperations().put(
        backupManagerService.putOperation(
                mCurrentOpToken, new Operation(OP_PENDING, this, OP_TYPE_BACKUP));
    }
    }

    /**
     * Remove this task from repository of running tasks.
@@ -358,7 +357,7 @@ public class PerformBackupTask implements BackupRestoreTask {
            // The package manager doesn't have a proper <application> etc, but since it's running
            // here in the system process we can just set up its agent directly and use a synthetic
            // BackupRequest.
            PackageManagerBackupAgent pmAgent = backupManagerService.makeMetadataAgent();
            BackupAgent pmAgent = backupManagerService.makeMetadataAgent();
            mStatus = invokeAgentForBackup(
                    PACKAGE_MANAGER_SENTINEL,
                    IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+2 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERA


import android.app.IBackupAgent;
import android.app.backup.BackupAgent;
import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.ApplicationInfo;
import android.content.pm.Signature;
@@ -76,7 +77,7 @@ public class PerformAdbRestoreTask implements Runnable {
    private final String mCurrentPassword;
    private final String mDecryptPassword;
    private final AtomicBoolean mLatchObject;
    private final PackageManagerBackupAgent mPackageManagerBackupAgent;
    private final BackupAgent mPackageManagerBackupAgent;
    private final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();

    private IFullBackupRestoreObserver mObserver;
+113 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 android.content.Context;
import android.os.ParcelFileDescriptor;

import java.io.File;
import java.io.IOException;

/**
 * Useful for spying in {@link BackupAgent} instances since their {@link BackupAgent#onBind()} is
 * final and always points to the original instance, instead of the spy.
 *
 * <p>To use, construct a spy of the desired {@link BackupAgent}, spying on the methods of interest.
 * Then, where you need to pass the agent, use {@link ForwardingBackupAgent#forward(BackupAgent)}
 * with the spy.
 */
public class ForwardingBackupAgent extends BackupAgent {
    /** Returns a {@link BackupAgent} that forwards method calls to {@code backupAgent}. */
    public static BackupAgent forward(BackupAgent backupAgent) {
        return new ForwardingBackupAgent(backupAgent);
    }

    private final BackupAgent mBackupAgent;

    private ForwardingBackupAgent(BackupAgent backupAgent) {
        mBackupAgent = backupAgent;
    }

    @Override
    public void onCreate() {
        mBackupAgent.onCreate();
    }

    @Override
    public void onDestroy() {
        mBackupAgent.onDestroy();
    }

    @Override
    public void onBackup(
            ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)
            throws IOException {
        mBackupAgent.onBackup(oldState, data, newState);
    }

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

    @Override
    public void onRestore(BackupDataInput data, long appVersionCode, ParcelFileDescriptor newState)
            throws IOException {
        mBackupAgent.onRestore(data, appVersionCode, newState);
    }

    @Override
    public void onFullBackup(FullBackupDataOutput data) throws IOException {
        mBackupAgent.onFullBackup(data);
    }

    @Override
    public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
        mBackupAgent.onQuotaExceeded(backupDataBytes, quotaBytes);
    }

    @Override
    public void onRestoreFile(
            ParcelFileDescriptor data, long size, File destination, int type, long mode, long mtime)
            throws IOException {
        mBackupAgent.onRestoreFile(data, size, destination, type, mode, mtime);
    }

    @Override
    protected void onRestoreFile(
            ParcelFileDescriptor data,
            long size,
            int type,
            String domain,
            String path,
            long mode,
            long mtime)
            throws IOException {
        mBackupAgent.onRestoreFile(data, size, type, domain, path, mode, mtime);
    }

    @Override
    public void onRestoreFinished() {
        mBackupAgent.onRestoreFinished();
    }

    @Override
    public void attach(Context context) {
        mBackupAgent.attach(context);
    }
}
+12 −28
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package com.android.server.backup;

import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startSilentBackupThread;
import static com.android.server.backup.testing.TransportData.backupTransport;
import static com.android.server.backup.testing.TransportData.d2dTransport;
import static com.android.server.backup.testing.TransportData.localTransport;
@@ -46,6 +46,7 @@ import android.os.PowerSaveState;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import com.android.server.backup.internal.BackupRequest;
import com.android.server.backup.testing.BackupManagerServiceTestUtils;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.backup.transport.TransportNotRegisteredException;
@@ -68,7 +69,6 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowContextWrapper;
import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.shadows.ShadowPackageManager;
import org.robolectric.shadows.ShadowSettings;
@@ -104,7 +104,10 @@ public class BackupManagerServiceTest {
        mTransport = backupTransport();
        mTransportName = mTransport.transportName;

        mBackupThread = startBackupThread(this::uncaughtException);
        // Unrelated exceptions are thrown in the backup thread. Until we mock everything properly
        // we should not fail tests because of this. This is not flakiness, the exceptions thrown
        // don't interfere with the tests.
        mBackupThread = startSilentBackupThread(TAG);
        mShadowBackupLooper = shadowOf(mBackupThread.getLooper());

        ContextWrapper context = RuntimeEnvironment.application;
@@ -113,8 +116,10 @@ public class BackupManagerServiceTest {
        mShadowContext = shadowOf(context);

        File cacheDir = mContext.getCacheDir();
        mBaseStateDir = new File(cacheDir, "base_state_dir");
        mDataDir = new File(cacheDir, "data_dir");
        // Corresponds to /data/backup
        mBaseStateDir = new File(cacheDir, "base_state");
        // Corresponds to /cache/backup_stage
        mDataDir = new File(cacheDir, "data");

        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
    }
@@ -126,13 +131,6 @@ public class BackupManagerServiceTest {
        ShadowBackupPolicyEnforcer.setMandatoryBackupTransport(null);
    }

    private void uncaughtException(Thread thread, Throwable e) {
        // Unrelated exceptions are thrown in the backup thread. Until we mock everything properly
        // we should not fail tests because of this. This is not flakiness, the exceptions thrown
        // don't interfere with the tests.
        ShadowLog.e(TAG, "Uncaught exception in test thread " + thread.getName(), e);
    }

    /* Tests for destination string */

    @Test
@@ -864,22 +862,8 @@ public class BackupManagerServiceTest {
    }

    private BackupManagerService createInitializedBackupManagerService() {
        BackupManagerService backupManagerService =
                new BackupManagerService(
                        mContext,
                        new Trampoline(mContext),
                        mBackupThread,
                        mBaseStateDir,
                        mDataDir,
                        mTransportManager);
        mShadowBackupLooper.runToEndOfTasks();
        // Handler instances have their own clock, so advancing looper (with runToEndOfTasks())
        // above does NOT advance the handlers' clock, hence whenever a handler post messages with
        // specific time to the looper the time of those messages will be before the looper's time.
        // To fix this we advance SystemClock as well since that is from where the handlers read
        // time.
        ShadowSystemClock.setCurrentTimeMillis(mShadowBackupLooper.getScheduler().getCurrentTime());
        return backupManagerService;
        return BackupManagerServiceTestUtils.createInitializedBackupManagerService(
                mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager);
    }

    private void setUpPowerManager(BackupManagerService backupManagerService) {
Loading