content: /*
   * 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 com.android.server.backup.keyvalue;
  
  import static android.app.backup.BackupManager.ERROR_AGENT_FAILURE;
  import static android.app.backup.BackupManager.ERROR_BACKUP_NOT_ALLOWED;
  import static android.app.backup.BackupManager.ERROR_PACKAGE_NOT_FOUND;
  import static android.app.backup.BackupManager.ERROR_TRANSPORT_ABORTED;
  import static android.app.backup.BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED;
  import static android.app.backup.BackupManager.SUCCESS;
  import static android.app.backup.ForwardingBackupAgent.forward;
  
  import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
  import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks;
  import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
  import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBinderCallerAndApplicationAsSystem;
  import static com.android.server.backup.testing.PackageData.PM_PACKAGE;
  import static com.android.server.backup.testing.PackageData.fullBackupPackage;
  import static com.android.server.backup.testing.PackageData.keyValuePackage;
  import static com.android.server.backup.testing.TestUtils.assertEventLogged;
  import static com.android.server.backup.testing.TestUtils.messagesInLooper;
  import static com.android.server.backup.testing.TestUtils.uncheck;
  import static com.android.server.backup.testing.TestUtils.waitUntil;
  import static com.android.server.backup.testing.TransportData.backupTransport;
  import static com.android.server.backup.testing.Utils.isFileNonEmpty;
  import static com.android.server.backup.testing.Utils.oneTimeIterable;
  import static com.android.server.backup.testing.Utils.transferStreamedData;
  
  import static com.google.common.truth.Truth.assertThat;
  
  import static org.mockito.ArgumentMatchers.any;
  import static org.mockito.ArgumentMatchers.anyInt;
  import static org.mockito.ArgumentMatchers.anyLong;
  import static org.mockito.ArgumentMatchers.argThat;
  import static org.mockito.ArgumentMatchers.eq;
  import static org.mockito.ArgumentMatchers.intThat;
  import static org.mockito.Mockito.doAnswer;
  import static org.mockito.Mockito.doNothing;
  import static org.mockito.Mockito.doReturn;
  import static org.mockito.Mockito.doThrow;
  import static org.mockito.Mockito.inOrder;
  import static org.mockito.Mockito.never;
  import static org.mockito.Mockito.reset;
  import static org.mockito.Mockito.spy;
  import static org.mockito.Mockito.times;
  import static org.mockito.Mockito.verify;
  import static org.mockito.Mockito.verifyZeroInteractions;
  import static org.mockito.Mockito.when;
  import static org.robolectric.Shadows.shadowOf;
  import static org.robolectric.shadow.api.Shadow.extract;
  import static org.testng.Assert.expectThrows;
  import static org.testng.Assert.fail;
  
  import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
  import static java.util.Collections.emptyList;
  import static java.util.stream.Collectors.toList;
  
  import android.annotation.Nullable;
  import android.app.Application;
  import android.app.IBackupAgent;
  import android.app.backup.BackupAgent;
  import android.app.backup.BackupDataInput;
  import android.app.backup.BackupDataOutput;
  import android.app.backup.BackupManager;
  import android.app.backup.BackupTransport;
  import android.app.backup.IBackupCallback;
  import android.app.backup.IBackupManager;
  import android.app.backup.IBackupManagerMonitor;
  import android.app.backup.IBackupObserver;
  import android.content.Context;
  import android.content.Intent;
  import android.content.pm.ApplicationInfo;
  import android.content.pm.PackageInfo;
  import android.content.pm.PackageManager;
  import android.content.pm.PackageManagerInternal;
  import android.net.Uri;
  import android.os.ConditionVariable;
  import android.os.DeadObjectException;
  import android.os.Handler;
  import android.os.Looper;
  import android.os.Message;
  import android.os.ParcelFileDescriptor;
  import android.os.RemoteException;
  import android.platform.test.annotations.Presubmit;
  import android.util.Pair;
  
  import com.android.internal.backup.IBackupTransport;
  import com.android.server.EventLogTags;
  import com.android.server.LocalServices;
  import com.android.server.backup.BackupRestoreTask;
  import com.android.server.backup.DataChangedJournal;
  import com.android.server.backup.KeyValueBackupJob;
  import com.android.server.backup.PackageManagerBackupAgent;
  import com.android.server.backup.TransportManager;
  import com.android.server.backup.UserBackupManagerService;
  import com.android.server.backup.internal.BackupHandler;
  import com.android.server.backup.internal.OnTaskFinishedListener;
  import com.android.server.backup.remote.RemoteCall;
  import com.android.server.backup.testing.PackageData;
  import com.android.server.backup.testing.TestUtils.ThrowingRunnable;
  import com.android.server.backup.testing.TransportData;
  import com.android.server.backup.testing.TransportTestUtils;
  import com.android.server.backup.testing.TransportTestUtils.TransportMock;
  import com.android.server.testing.shadows.FrameworkShadowLooper;
  import com.android.server.testing.shadows.ShadowApplicationPackageManager;
  import com.android.server.testing.shadows.ShadowBackupDataInput;
  import com.android.server.testing.shadows.ShadowBackupDataOutput;
  import com.android.server.testing.shadows.ShadowEventLog;
  
  import com.google.common.truth.IterableSubject;
  
  import org.junit.After;
  import org.junit.Before;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.mockito.ArgumentMatcher;
  import org.mockito.InOrder;
  import org.mockito.Mock;
  import org.mockito.MockitoAnnotations;
  import org.mockito.invocation.InvocationOnMock;
  import org.mockito.stubbing.Answer;
  import org.robolectric.RobolectricTestRunner;
  import org.robolectric.RuntimeEnvironment;
  import org.robolectric.annotation.Config;
  import org.robolectric.shadows.ShadowLooper;
  import org.robolectric.shadows.ShadowPackageManager;
  import org.robolectric.shadows.ShadowQueuedWork;
  
  import java.io.ByteArrayOutputStream;
  import java.io.File;
  import java.io.FileDescriptor;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.TimeoutException;
  import java.util.stream.Stream;
  
  // TODO: Test agents timing out
  @RunWith(RobolectricTestRunner.class)
  @Config(
          shadows = {
              FrameworkShadowLooper.class,
              ShadowApplicationPackageManager.class,
              ShadowBackupDataInput.class,
              ShadowBackupDataOutput.class,
              ShadowEventLog.class,
              ShadowQueuedWork.class
          })
  @Presubmit
  public class KeyValueBackupTaskTest {
      private static final PackageData PACKAGE_1 = keyValuePackage(1);
      private static final PackageData PACKAGE_2 = keyValuePackage(2);
      private static final String BACKUP_AGENT_SHARED_PREFS_SYNCHRONIZER_CLASS =
              "android.app.backup.BackupAgent$SharedPrefsSynchronizer";
      private static final int USER_ID = 10;
  
      @Mock private TransportManager mTransportManager;
      @Mock private DataChangedJournal mOldJournal;
      @Mock private IBackupObserver mObserver;
      @Mock private IBackupManagerMonitor mMonitor;
      @Mock private OnTaskFinishedListener mListener;
      @Mock private PackageManagerInternal mPackageManagerInternal;
      private UserBackupManagerService mBackupManagerService;
      private TransportData mTransport;
      private ShadowLooper mShadowBackupLooper;
      private Handler mBackupHandler;
      private UserBackupManagerService.BackupWakeLock mWakeLock;
      private KeyValueBackupReporter mReporter;
      private PackageManager mPackageManager;
      private ShadowPackageManager mShadowPackageManager;
      private FakeIBackupManager mBackupManager;
      private File mBaseStateDir;
      private File mDataDir;
      private Application mApplication;
      private Looper mMainLooper;
      private FrameworkShadowLooper mShadowMainLooper;
      private Context mContext;
  
      @Before
      public void setUp() throws Exception {
          MockitoAnnotations.initMocks(this);
  
          mTransport = backupTransport();
  
          mApplication = RuntimeEnvironment.application;
          mContext = mApplication;
  
          mMainLooper = Looper.getMainLooper();
          mShadowMainLooper = extract(mMainLooper);
  
          File cacheDir = mApplication.getCacheDir();
          // Corresponds to /data/backup
          mBaseStateDir = new File(cacheDir, "base_state");
          // Corresponds to /cache/backup_stage
          mDataDir = new File(cacheDir, "data");
          // We create here simulating init.rc
          mDataDir.mkdirs();
          assertThat(mDataDir.isDirectory()).isTrue();
  
          mPackageManager = mApplication.getPackageManager();
          mShadowPackageManager = shadowOf(mPackageManager);
  
          mWakeLock = createBackupWakeLock(mApplication);
          mBackupManager = spy(FakeIBackupManager.class);
  
          // Needed to be able to use a real BMS instead of a mock
          setUpBinderCallerAndApplicationAsSystem(mApplication);
          mBackupManagerService =
                  spy(createUserBackupManagerServiceAndRunTasks(
                          USER_ID, mContext, mBaseStateDir, mDataDir, mTransportManager));
          setUpBackupManagerServiceBasics(
                  mBackupManagerService,
                  mApplication,
                  mTransportManager,
                  mPackageManager,
                  mBackupManagerService.getBackupHandler(),
                  mWakeLock,
                  mBackupManagerService.getAgentTimeoutParameters());
          when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
          when(mBackupManagerService.getDataDir()).thenReturn(mDataDir);
          when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
  
          mBackupHandler = mBackupManagerService.getBackupHandler();
          mShadowBackupLooper = shadowOf(mBackupHandler.getLooper());
          ShadowEventLog.setUp();
          mReporter = spy(new KeyValueBackupReporter(mBackupManagerService, mObserver, mMonitor));
  
          when(mPackageManagerInternal.getApplicationEnabledState(any(), anyInt()))
                  .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
          LocalServices.removeServiceForTest(PackageManagerInternal.class);
          LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
      }
  
      @After
      public void tearDown() throws Exception {
          ShadowBackupDataInput.reset();
          ShadowApplicationPackageManager.reset();
      }
  
      @Test
      public void testRunTask_whenQueueEmpty_updatesBookkeeping() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(mBackupManagerService.getCurrentToken()).thenReturn(0L);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true);
  
          runTask(task);
  
          assertThat(mBackupManagerService.getPendingInits()).isEmpty();
          assertThat(mBackupManagerService.isBackupRunning()).isFalse();
          assertThat(mBackupManagerService.getCurrentOperations().size()).isEqualTo(0);
          verify(mOldJournal).delete();
      }
  
      @Test
      public void testRunTask_whenQueueEmpty_releasesWakeLock() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(mBackupManagerService.getCurrentToken()).thenReturn(0L);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true);
  
          runTask(task);
  
          assertThat(mWakeLock.isHeld()).isFalse();
      }
  
      @Test
      public void testRunTask_whenQueueEmpty_doesNotProduceData() throws Exception {
          TransportMock transportMock = setUpTransport(mTransport);
          when(mBackupManagerService.getCurrentToken()).thenReturn(0L);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true);
  
          runTask(task);
  
          assertDirectory(getStateDirectory(mTransport)).isEmpty();
          assertDirectory(mDataDir.toPath()).isEmpty();
      }
  
      @Test
      public void testRunTask_whenQueueEmpty_doesNotCallTransport() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(mBackupManagerService.getCurrentToken()).thenReturn(0L);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true);
  
          runTask(task);
  
          verify(transportMock.transport, never()).initializeDevice();
          verify(transportMock.transport, never()).performBackup(any(), any(), anyInt());
          verify(transportMock.transport, never()).finishBackup();
      }
  
      @Test
      public void testRunTask_whenQueueEmpty_notifiesCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(mBackupManagerService.getCurrentToken()).thenReturn(0L);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true);
  
          runTask(task);
  
          verify(mListener).onFinished(any());
          verify(mObserver, never()).onResult(any(), anyInt());
          verify(mObserver).backupFinished(SUCCESS);
      }
  
      @Test
      public void testRunTask_whenQueueEmpty_doesNotChangeStateFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true);
          Files.write(getStateFile(mTransport, PM_PACKAGE), "pmState".getBytes());
          Files.write(getStateFile(mTransport, PACKAGE_1), "packageState".getBytes());
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PM_PACKAGE)))
                  .isEqualTo("pmState".getBytes());
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("packageState".getBytes());
      }
  
      /**
       * Do not update backup token if the backup queue was empty
       */
      @Test
      public void testRunTask_whenQueueEmptyOnFirstBackup_doesNotUpdateCurrentToken()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true);
          mBackupManagerService.setCurrentToken(0L);
          when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L);
  
          runTask(task);
  
          assertThat(mBackupManagerService.getCurrentToken()).isEqualTo(0L);
      }
  
      @Test
      public void testRunTask_whenOnePackageAndTransportUnavailable() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport.unavailable());
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mListener).onFinished(any());
          verify(mObserver).backupFinished(ERROR_TRANSPORT_ABORTED);
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenOnePackage_logsBackupStartEvent() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertEventLogged(EventLogTags.BACKUP_START, mTransport.transportName);
      }
  
      @Test
      public void testRunTask_whenOnePackage_releasesWakeLock() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertThat(mWakeLock.isHeld()).isFalse();
      }
  
      @Test
      public void testRunTask_whenOnePackage_cleansUpPmFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertCleansUpFiles(mTransport, PM_PACKAGE);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsTransportErrorForPm_cleansUpPmFiles()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertCleansUpFiles(mTransport, PM_PACKAGE);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsTransportErrorForPm_resetsBackupState()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
      }
  
      @Test
      public void testRunTask_whenOnePackage_updatesBookkeeping() throws Exception {
          // Transport has to be initialized to not reset current token
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          mBackupManagerService.setCurrentToken(0L);
          when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertThat(mBackupManagerService.getPendingInits()).isEmpty();
          assertThat(mBackupManagerService.isBackupRunning()).isFalse();
          assertThat(mBackupManagerService.getCurrentOperations().size()).isEqualTo(0);
          assertThat(mBackupManagerService.getCurrentToken()).isEqualTo(1234L);
          verify(mBackupManagerService).writeRestoreTokens();
          verify(mOldJournal).delete();
      }
  
      @Test
      public void testRunTask_whenPackageWithOldStateAndIncremental_passesOldStateToAgent()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          assertThat(agentMock.oldState).isEqualTo("oldState".getBytes());
      }
  
      @Test
      public void testRunTask_whenPackageWithOldStateAndNonIncremental_passesEmptyOldStateToAgent()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          assertThat(agentMock.oldState).isEqualTo(new byte[0]);
      }
  
      @Test
      public void testRunTask_whenNonPmPackageAndNonIncremental_doesNotBackUpPm() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
  
          runTask(task);
  
          verify(pmAgent, never()).onBackup(any(), any(), any());
      }
  
      @Test
      public void testRunTask_whenNonPmPackageAndPmAndNonIncremental_backsUpPm() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task =
                  createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE);
  
          runTask(task);
  
          verify(pmAgent).onBackup(any(), any(), any());
      }
  
      @Test
      public void testRunTask_whenNonPmPackageAndIncremental_backsUpPm() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1);
  
          runTask(task);
  
          verify(pmAgent).onBackup(any(), any(), any());
      }
  
      @Test
      public void testRunTask_whenOnePackageAndNoPmState_initializesTransportAndResetsState()
              throws Exception {
          TransportMock transportMock = setUpTransport(mTransport);
          // Need 2 packages to be able to verify state of package not involved in the task
          setUpAgentsWithData(PACKAGE_1, PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          deletePmStateFile();
          Files.write(getStateFile(mTransport, PACKAGE_2), "package2State".getBytes());
  
          runTask(task);
  
          verify(transportMock.transport).initializeDevice();
          verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
          // Verifying that it deleted all the states (can't verify package 1 because it generated a
          // new state in this task execution)
          assertThat(Files.exists(getStateFile(mTransport, PACKAGE_2))).isFalse();
          assertEventLogged(EventLogTags.BACKUP_INITIALIZE);
      }
  
      @Test
      public void testRunTask_whenOnePackageAndWithPmState_doesNotInitializeTransportOrResetState()
              throws Exception {
          TransportMock transportMock = setUpTransport(mTransport);
          setUpAgentsWithData(PACKAGE_1, PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          createPmStateFile();
          Files.write(getStateFile(mTransport, PACKAGE_2), "package2State".getBytes());
  
          runTask(task);
  
          verify(transportMock.transport, never()).initializeDevice();
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_2)))
                  .isEqualTo("package2State".getBytes());
      }
  
      @Test
      public void testRunTask_whenTransportReturnsErrorForInitialization() throws Exception {
          TransportMock transportMock = setUpTransport(mTransport);
          when(transportMock.transport.initializeDevice())
                  .thenReturn(BackupTransport.TRANSPORT_ERROR);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          deletePmStateFile();
  
          runTask(task);
  
          // First for initialization and second because of the transport failure
          verify(mBackupManagerService, times(2))
                  .resetBackupState(getStateDirectory(mTransport).toFile());
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
          verify(transportMock.transport, never()).performBackup(any(), any(), anyInt());
          assertBackupPendingFor(PACKAGE_1);
          assertEventLogged(EventLogTags.BACKUP_TRANSPORT_FAILURE, "(initialize)");
      }
  
      @Test
      public void testRunTask_whenTransportThrowsDuringInitialization() throws Exception {
          TransportMock transportMock = setUpTransport(mTransport);
          when(transportMock.transport.initializeDevice()).thenThrow(RemoteException.class);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          deletePmStateFile();
  
          runTask(task);
  
          // First for initialization and second because of the transport failure
          verify(mBackupManagerService, times(2))
                  .resetBackupState(getStateDirectory(mTransport).toFile());
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
          verify(transportMock.transport, never()).performBackup(any(), any(), anyInt());
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenPackageUnknown() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          // Not calling setUpAgent() for PACKAGE_1
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_PACKAGE_NOT_FOUND);
          verify(mObserver).backupFinished(SUCCESS);
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenFirstPackageUnknown_callsTransportForSecondPackage()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          // Not calling setUpAgent() for PACKAGE_1
          setUpAgentWithData(PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenPackageNotEligibleForBackup() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1.backupNotAllowed());
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_BACKUP_NOT_ALLOWED);
          verify(mObserver).backupFinished(SUCCESS);
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenFirstPackageNotEligibleForBackup_callsTransportForSecondPackage()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentsWithData(PACKAGE_1.backupNotAllowed(), PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenPackageDoesFullBackup() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          PackageData packageData = fullBackupPackage(1);
          AgentMock agentMock = setUpAgentWithData(packageData);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, packageData);
  
          runTask(task);
  
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
          verify(agentMock.agent, never()).onFullBackup(any());
          verify(mObserver).onResult(packageData.packageName, ERROR_BACKUP_NOT_ALLOWED);
          verify(mObserver).backupFinished(SUCCESS);
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenFirstPackageDoesFullBackup_callsTransportForSecondPackage()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          PackageData packageData = fullBackupPackage(1);
          setUpAgentsWithData(packageData, PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, packageData, PACKAGE_2);
  
          runTask(task);
  
          verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenPackageIsStopped() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1.stopped());
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_BACKUP_NOT_ALLOWED);
          verify(mObserver).backupFinished(SUCCESS);
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenFirstPackageIsStopped_callsTransportForSecondPackage()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentsWithData(PACKAGE_1.stopped(), PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenCallingAgent_setsWakeLockWorkSource() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      // In production (for non-system agents) the call is asynchronous, but here is
                      // synchronous, so it's fine to verify here.
                      // Verify has set work source and hasn't unset yet.
                      verify(mBackupManagerService)
                              .setWorkSource(
                                      argThat(workSource -> workSource.get(0) == PACKAGE_1.uid));
                      verify(mBackupManagerService, never()).setWorkSource(null);
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          // More verifications inside agent call above
          verify(mBackupManagerService).setWorkSource(null);
      }
  
      /**
       * Agent unavailable means {@link UserBackupManagerService#bindToAgentSynchronous(ApplicationInfo,
       * int)} returns {@code null}.
       *
       * @see #setUpAgent(PackageData)
       */
      @Test
      public void testRunTask_whenAgentUnavailable() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1.unavailable());
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).setWorkSource(null);
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
          verify(mObserver).backupFinished(BackupManager.SUCCESS);
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenSecondAgentUnavailable_commitsFirstAgentState() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          setUpAgent(PACKAGE_2.unavailable());
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1))).isEqualTo(
                  "newState".getBytes());
      }
  
      @Test
      public void testRunTask_whenNonIncrementalAndAgentUnavailable() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1.unavailable());
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).setWorkSource(null);
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
          verify(mObserver).backupFinished(BackupManager.SUCCESS);
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenBindToAgentThrowsSecurityException() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          doThrow(SecurityException.class)
                  .when(mBackupManagerService)
                  .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt());
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).setWorkSource(null);
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
          verify(mObserver).backupFinished(BackupManager.SUCCESS);
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenNonIncrementalAndBindToAgentThrowsSecurityException() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          doThrow(SecurityException.class)
                  .when(mBackupManagerService)
                  .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt());
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).setWorkSource(null);
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
          verify(mObserver).backupFinished(BackupManager.SUCCESS);
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportGetBackupQuotaThrows_notifiesCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.getBackupQuota(PACKAGE_1.packageName, false))
                  .thenThrow(DeadObjectException.class);
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mObserver, never()).onResult(eq(PACKAGE_1.packageName), anyInt());
          verify(mObserver).backupFinished(ERROR_TRANSPORT_ABORTED);
          verify(mListener).onFinished(any());
      }
  
      @Test
      public void testRunTask_whenTransportGetBackupQuotaThrows_cleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.getBackupQuota(PACKAGE_1.packageName, false))
                  .thenThrow(DeadObjectException.class);
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).setWorkSource(null);
          verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
      }
  
      @Test
      public void testRunTask_whenTransportGetBackupQuotaThrows_doesNotTouchFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.getBackupQuota(PACKAGE_1.packageName, false))
                  .thenThrow(DeadObjectException.class);
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "packageState".getBytes());
  
          runTask(task);
  
          assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
          assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("packageState".getBytes());
      }
  
      @Test
      public void testRunTask_whenTransportGetBackupQuotaThrows_revertsTask() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.getBackupQuota(PACKAGE_1.packageName, false))
                  .thenThrow(DeadObjectException.class);
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertTaskReverted(transportMock, PACKAGE_1);
      }
  
      /**
       * For local agents the exception is thrown in our stack, before {@link RemoteCall} has a chance
       * to complete cleanly.
       */
      // TODO: When RemoteCall spins up a new thread the assertions on this method should be the same
      // as the methods below (non-local call).
      @Test
      public void testRunTask_whenLocalAgentOnBackupThrows_setsNullWorkSource() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      throw new RuntimeException();
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).setWorkSource(null);
      }
  
      @Test
      public void testRunTask_whenLocalAgentOnBackupThrows_reportsCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      throw new RuntimeException();
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
          verify(mObserver).backupFinished(SUCCESS);
          verify(mReporter)
                  .onCallAgentDoBackupError(
                          eq(PACKAGE_1.packageName), eq(true), any(RuntimeException.class));
          assertEventLogged(
                  EventLogTags.BACKUP_AGENT_FAILURE,
                  PACKAGE_1.packageName,
                  new RuntimeException().toString());
      }
  
      @Test
      public void testRunTask_whenLocalAgentOnBackupThrows_doesNotUpdateBookkeping()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      throw new RuntimeException();
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenAgentOnBackupThrows_reportsCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          remoteAgentOnBackupThrows(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      throw new RuntimeException();
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mReporter).onAgentResultError(argThat(packageInfo(PACKAGE_1)));
      }
  
      @Test
      public void testRunTask_whenAgentOnBackupThrows_updatesBookkeeping() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          remoteAgentOnBackupThrows(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      throw new RuntimeException();
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertBackupPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenAgentOnBackupThrows_doesNotCallTransport() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          remoteAgentOnBackupThrows(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      throw new RuntimeException();
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenAgentOnBackupThrows_updatesFilesAndCleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          remoteAgentOnBackupThrows(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      throw new RuntimeException();
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("oldState".getBytes());
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportProvidesFlags_passesThemToTheAgent() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
          when(transportMock.transport.getTransportFlags()).thenReturn(flags);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(agentMock.agent)
                  .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
      }
  
      @Test
      public void testRunTask_whenTransportDoesNotProvidesFlags() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(agentMock.agent).onBackup(any(), argThat(dataOutputWithTransportFlags(0)), any());
      }
  
      @Test
      public void testRunTask_whenTransportProvidesFlagsAndMultipleAgents_passesToAll()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
          when(transportMock.transport.getTransportFlags()).thenReturn(flags);
          List<AgentMock> agentMocks = setUpAgents(PACKAGE_1, PACKAGE_2);
          BackupAgent agent1 = agentMocks.get(0).agent;
          BackupAgent agent2 = agentMocks.get(1).agent;
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(agent1).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
          verify(agent2).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
      }
  
      @Test
      public void testRunTask_whenTransportChangeFlagsAfterTaskCreation() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
          when(transportMock.transport.getTransportFlags()).thenReturn(flags);
  
          runTask(task);
  
          verify(agentMock.agent)
                  .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
      }
  
      @Test
      public void testRunTask_whenAgentUsesProhibitedKey_failsAgent() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      char prohibitedChar = 0xff00;
                      writeData(dataOutput, prohibitedChar + "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(agentMock.agentBinder).fail(any());
          verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
      }
  
      @Test
      public void testRunTask_whenAgentUsesProhibitedKey_updatesFilesAndCleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      char prohibitedChar = 0xff00;
                      writeData(dataOutput, prohibitedChar + "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("oldState".getBytes());
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenAgentUsesProhibitedKey_doesNotCallTransport() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      char prohibitedChar = 0xff00;
                      writeData(dataOutput, prohibitedChar + "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenAgentUsesProhibitedKey_notifiesCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      char prohibitedChar = 0xff00;
                      writeData(dataOutput, prohibitedChar + "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          verify(mListener).onFinished(any());
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
          verify(mObserver).backupFinished(SUCCESS);
      }
  
      @Test
      public void testRunTask_whenAgentUsesProhibitedKey_logsAgentFailureEvent() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      char prohibitedChar = 0xff00;
                      writeData(dataOutput, prohibitedChar + "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          assertEventLogged(EventLogTags.BACKUP_AGENT_FAILURE, PACKAGE_1.packageName, "bad key");
      }
  
      @Test
      public void testRunTask_whenFirstAgentUsesProhibitedKeyButLastAgentUsesPermittedKey()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          List<AgentMock> agentMocks = setUpAgents(PACKAGE_1, PACKAGE_2);
          AgentMock agentMock1 = agentMocks.get(0);
          AgentMock agentMock2 = agentMocks.get(1);
          agentOnBackupDo(
                  agentMock1,
                  (oldState, dataOutput, newState) -> {
                      char prohibitedChar = 0xff00;
                      writeData(dataOutput, prohibitedChar + "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          agentOnBackupDo(
                  agentMock2,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(mListener).onFinished(any());
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
          verify(agentMock1.agentBinder).fail(any());
          verify(mObserver).onResult(PACKAGE_2.packageName, SUCCESS);
          verify(mObserver).backupFinished(SUCCESS);
      }
  
      @Test
      public void testRunTask_whenAgentDoesNotWriteData_doesNotCallTransport() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      // No-op
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenAgentDoesNotWriteData_logsEvents() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      // No-op
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertEventLogged(EventLogTags.BACKUP_PACKAGE, PACKAGE_1.packageName, 0L);
          verify(mBackupManagerService).logBackupComplete(PACKAGE_1.packageName);
      }
  
      @Test
      public void testRunTask_whenAgentDoesNotWriteData_notifiesCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      // No-op
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mObserver).onResult(PACKAGE_1.packageName, SUCCESS);
          verify(mObserver).backupFinished(SUCCESS);
      }
  
      @Test
      public void testRunTask_whenAgentDoesNotWriteData_updatesBookkeeping() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      // No-op
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenAgentDoesNotWriteData_updatesFilesAndCleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      // No-op
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1))).isEqualTo(new byte[0]);
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenAgentWritesData_callsTransportPerformBackupWithAgentData()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          Path backupDataPath = createTemporaryFile();
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .then(copyBackupDataTo(backupDataPath));
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key1", "data1".getBytes());
                      writeData(dataOutput, "key2", "data2".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
          // Now verify data sent
          try (FileInputStream inputStream = new FileInputStream(backupDataPath.toFile())) {
              BackupDataInput backupData = new BackupDataInput(inputStream.getFD());
              assertDataHasKeyValue(backupData, "key1", "data1".getBytes());
              assertDataHasKeyValue(backupData, "key2", "data2".getBytes());
              assertThat(backupData.readNextHeader()).isFalse();
          }
      }
  
      @Test
      public void testRunTask_whenPmAgentWritesData_callsTransportPerformBackupWithAgentData()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          Path backupDataPath = createTemporaryFile();
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
                  .then(copyBackupDataTo(backupDataPath));
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          agentOnBackupDo(
                  pmAgent,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key1", "data1".getBytes());
                      writeData(dataOutput, "key2", "data2".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PM_PACKAGE)), any(), anyInt());
          try (FileInputStream inputStream = new FileInputStream(backupDataPath.toFile())) {
              BackupDataInput backupData = new BackupDataInput(inputStream.getFD());
              assertDataHasKeyValue(backupData, "key1", "data1".getBytes());
              assertDataHasKeyValue(backupData, "key2", "data2".getBytes());
              assertThat(backupData.readNextHeader()).isFalse();
          }
      }
  
      @Test
      public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_OK);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          // First for PM, then for the package
          verify(transportMock.transport, times(2)).finishBackup();
      }
  
      @Test
      public void testRunTask_whenFinishBackupSucceeds_updatesFilesAndCleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("newState".getBytes());
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenFinishBackupSucceedsForPm_cleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          agentOnBackupDo(
                  pmAgent,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PM_PACKAGE)))
                  .isEqualTo("newState".getBytes());
          assertCleansUpFiles(mTransport, PM_PACKAGE);
          // We don't unbind PM
          verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
      }
  
      @Test
      public void testRunTask_whenFinishBackupSucceedsForPm_doesNotUnbindPm() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          agentOnBackupDo(
                  pmAgent,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService, never()).unbindAgent(argThat(applicationInfo(PM_PACKAGE)));
      }
  
      @Test
      public void testRunTask_whenFinishBackupSucceeds_logsBackupPackageEvent() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          Path backupData = createTemporaryFile();
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .then(copyBackupDataTo(backupData));
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertEventLogged(
                  EventLogTags.BACKUP_PACKAGE, PACKAGE_1.packageName, Files.size(backupData));
      }
  
      @Test
      public void testRunTask_whenFinishBackupSucceeds_notifiesCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).logBackupComplete(PACKAGE_1.packageName);
          verify(mObserver).onResult(PACKAGE_1.packageName, SUCCESS);
          verify(mObserver).backupFinished(SUCCESS);
          verify(mListener).onFinished(any());
      }
  
      @Test
      public void testRunTask_whenFinishBackupSucceeds_updatesBookkeeping() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportRejectsPackage_doesNotCallFinishBackup() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          // Called only for PM
          verify(transportMock.transport, times(1)).finishBackup();
      }
  
      @Test
      public void testRunTask_whenTransportRejectsPackage_updatesFilesAndCleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("oldState".getBytes());
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportRejectsPackage_logsAgentFailureEvent() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertEventLogged(
                  EventLogTags.BACKUP_AGENT_FAILURE, PACKAGE_1.packageName, "Transport rejected");
      }
  
      @Test
      public void testRunTask_whenTransportRejectsPackage_notifiesCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_TRANSPORT_PACKAGE_REJECTED);
          verify(mObserver).backupFinished(SUCCESS);
          verify(mListener).onFinished(any());
      }
  
      @Test
      public void testRunTask_whenTransportRejectsPackage_updatesBookkeeping() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportRejectsFirstPackageButLastSucceeds() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_OK);
          setUpAgentsWithData(PACKAGE_1, PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_TRANSPORT_PACKAGE_REJECTED);
          verify(mObserver).onResult(PACKAGE_2.packageName, SUCCESS);
          verify(mObserver).backupFinished(SUCCESS);
      }
  
      @Test
      public void testRunTask_whenTransportRejectsLastPackageButFirstSucceeds() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_OK);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
          setUpAgentsWithData(PACKAGE_1, PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(mObserver).onResult(PACKAGE_1.packageName, SUCCESS);
          verify(mObserver).onResult(PACKAGE_2.packageName, ERROR_TRANSPORT_PACKAGE_REJECTED);
          verify(mObserver).backupFinished(SUCCESS);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsQuotaExceeded_callsAgentOnQuotaExceeded()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.getBackupQuota(PACKAGE_1.packageName, false))
                  .thenReturn(1234L);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          InOrder inOrder = inOrder(agentMock.agent, mBackupManagerService);
          inOrder.verify(agentMock.agent).onQuotaExceeded(anyLong(), eq(1234L));
          inOrder.verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
      }
  
      @Test
      public void testRunTask_whenTransportReturnsQuotaExceeded_updatesBookkeeping()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertBackupNotPendingFor(PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsQuotaExceeded_notifiesAndLogs() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.getBackupQuota(PACKAGE_1.packageName, false))
                  .thenReturn(1234L);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mObserver)
                  .onResult(PACKAGE_1.packageName, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
          verify(mObserver).backupFinished(SUCCESS);
          assertEventLogged(EventLogTags.BACKUP_QUOTA_EXCEEDED, PACKAGE_1.packageName);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsQuotaExceeded_cleansUpFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitialized_cleansUpFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertThat(isFileNonEmpty(getStateFile(mTransport, PACKAGE_1))).isFalse();
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitialized_reportsCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mReporter).onPackageBackupTransportFailure(PACKAGE_1.packageName);
          verify(mReporter).onTransportNotInitialized();
          verify(mReporter).onBackupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitializedForPm_reportsCorrectly()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mReporter).onPackageBackupTransportFailure(PM_PACKAGE.packageName);
          verify(mReporter).onTransportNotInitialized();
          verify(mReporter).onBackupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitialized_doesNotCallSecondAgent()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
  
          runTask(task);
  
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitialized_revertsTask() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertTaskReverted(transportMock, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitialized_triggersTransportInitialization()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertThat(mBackupManagerService.getPendingInits()).contains(mTransport.transportName);
          verify(mBackupManagerService).backupNow();
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitialized_cleansUpPmStateFile()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PM_PACKAGE), "pmState".getBytes());
  
          runTask(task);
  
          assertThat(Files.exists(getStateFile(mTransport, PM_PACKAGE))).isFalse();
      }
  
      @Test
      public void testRunTask_whenTransportReturnsNotInitializedForPm_cleansUpPmStateFile()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PM_PACKAGE), "pmState".getBytes());
  
          runTask(task);
  
          assertThat(Files.exists(getStateFile(mTransport, PM_PACKAGE))).isFalse();
      }
  
      @Test
      public void
              testRunTask_whenTransportReturnsNotInitializedAndThrowsWhenQueryingName_reportsCorrectly()
                      throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(any(), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NOT_INITIALIZED);
          // First one is in startTask(), second is the one we want.
          when(transportMock.transport.name())
                  .thenReturn(mTransport.transportName)
                  .thenThrow(DeadObjectException.class);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mReporter).onPendingInitializeTransportError(any(DeadObjectException.class));
          verify(mReporter).onBackupFinished(ERROR_TRANSPORT_ABORTED);
      }
  
      @Test
      public void testRunTask_whenNonIncrementalAndTransportRequestsNonIncremental()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
          // Delete to be non-incremental
          Files.deleteIfExists(getStateFile(mTransport, PACKAGE_1));
  
          runTask(task);
  
          // Error because it was non-incremental already, so transport can't request it
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_TRANSPORT_ABORTED);
          verify(mObserver).backupFinished(ERROR_TRANSPORT_ABORTED);
      }
  
      @Test
      public void testRunTask_whenIncrementalAndTransportRequestsNonIncremental() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          Path incrementalData = createTemporaryFile();
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)),
                          any(),
                          intThat(flags -> (flags & BackupTransport.FLAG_INCREMENTAL) != 0)))
                  .thenAnswer(
                          copyBackupDataAndReturn(
                                  incrementalData,
                                  BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED));
          Path nonIncrementalData = createTemporaryFile();
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)),
                          any(),
                          intThat(flags -> (flags & BackupTransport.FLAG_NON_INCREMENTAL) != 0)))
                  .thenAnswer(
                          copyBackupDataAndReturn(nonIncrementalData, BackupTransport.TRANSPORT_OK));
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      // agentMock.oldState has already been updated by now.
                      if (agentMock.oldState.length > 0) {
                          writeData(dataOutput, "key", "dataForIncremental".getBytes());
                          writeState(newState, "stateForIncremental".getBytes());
                      } else {
                          writeData(dataOutput, "key", "dataForNonIncremental".getBytes());
                          writeState(newState, "stateForNonIncremental".getBytes());
                      }
                  });
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1);
          // Write state to be incremental
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          verify(agentMock.agent, times(2)).onBackup(any(), any(), any());
          byte[] oldStateDuringIncremental = agentMock.oldStateHistory.get(0);
          byte[] oldStateDuringNonIncremental = agentMock.oldStateHistory.get(1);
          assertThat(oldStateDuringIncremental).isEqualTo("oldState".getBytes());
          assertThat(oldStateDuringNonIncremental).isEqualTo(new byte[0]);
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("stateForNonIncremental".getBytes());
          try (FileInputStream inputStream = new FileInputStream(incrementalData.toFile())) {
              BackupDataInput backupData = new BackupDataInput(inputStream.getFD());
              assertDataHasKeyValue(backupData, "key", "dataForIncremental".getBytes());
              assertThat(backupData.readNextHeader()).isFalse();
          }
          try (FileInputStream inputStream = new FileInputStream(nonIncrementalData.toFile())) {
              BackupDataInput backupData = new BackupDataInput(inputStream.getFD());
              assertDataHasKeyValue(backupData, "key", "dataForNonIncremental".getBytes());
              assertThat(backupData.readNextHeader()).isFalse();
          }
          verify(mObserver).onResult(PACKAGE_1.packageName, SUCCESS);
          verify(mObserver).backupFinished(SUCCESS);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsError_notifiesCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_ERROR);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_TRANSPORT_ABORTED);
          verify(mObserver).backupFinished(ERROR_TRANSPORT_ABORTED);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsError_logsBackupTransportFailureEvent()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_ERROR);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertEventLogged(EventLogTags.BACKUP_TRANSPORT_FAILURE, PACKAGE_1.packageName);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsError_revertsTask() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_ERROR);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertTaskReverted(transportMock, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportReturnsError_updatesFilesAndCleansUp() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenReturn(BackupTransport.TRANSPORT_ERROR);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          Files.write(getStateFile(mTransport, PACKAGE_1), "oldState".getBytes());
  
          runTask(task);
  
          assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
                  .isEqualTo("oldState".getBytes());
          assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenTransportGetBackupQuotaThrowsForPm() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(transportMock.transport.getBackupQuota(PM_PACKAGE.packageName, false))
                  .thenThrow(DeadObjectException.class);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mListener).onFinished(any());
          verify(mObserver).backupFinished(ERROR_TRANSPORT_ABORTED);
          assertEventLogged(
                  EventLogTags.BACKUP_AGENT_FAILURE,
                  PM_PACKAGE.packageName,
                  new DeadObjectException().toString());
      }
  
      @Test
      public void testRunTask_whenPmAgentFails_reportsCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
          when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mListener).onFinished(any());
          verify(mObserver).backupFinished(eq(ERROR_TRANSPORT_ABORTED));
          assertEventLogged(
                  EventLogTags.BACKUP_AGENT_FAILURE,
                  PM_PACKAGE.packageName,
                  new RuntimeException().toString());
      }
  
      @Test
      public void testRunTask_whenPmAgentFails_revertsTask() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
          doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertTaskReverted(transportMock, PACKAGE_1);
      }
  
      @Test
      public void testRunTask_whenPmAgentFails_cleansUpFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
          doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          assertCleansUpFiles(mTransport, PM_PACKAGE);
      }
  
      @Test
      public void testRunTask_whenPmAgentFails_resetsBackupState() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
          doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          runTask(task);
  
          verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
      }
  
      @Test
      public void testRunTask_whenMarkCancelDuringPmOnBackup_resetsBackupState() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          agentOnBackupDo(
                  pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
  
          runTask(task);
  
          verify(mBackupManagerService).resetBackupState(getStateDirectory(mTransport).toFile());
      }
  
      @Test
      public void testRunTask_whenMarkCancelDuringPmOnBackup_cleansUpFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgent(PACKAGE_1);
          BackupAgent pmAgent = spy(createPmAgent());
          doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          agentOnBackupDo(
                  pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
  
          runTask(task);
  
          assertCleansUpFiles(mTransport, PM_PACKAGE);
      }
  
      @Test
      public void testRunTask_whenBackupRunning_doesNotThrow() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          when(mBackupManagerService.isBackupOperationInProgress()).thenReturn(true);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock);
  
          runTask(task);
      }
  
      @Test
      public void testRunTask_whenReadingBackupDataThrows_reportsCorrectly() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          // We don't validate PM's data, so it will only throw in PACKAGE_1
          ShadowBackupDataInput.throwInNextHeaderRead();
  
          runTask(task);
  
          verify(mReporter).onAgentDataError(eq(PACKAGE_1.packageName), any());
      }
  
      @Test
      public void testRunTask_whenReadingBackupDataThrows_doesNotCallTransport() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          ShadowBackupDataInput.throwInNextHeaderRead();
  
          runTask(task);
  
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenReadingBackupDataThrows_doesNotCallSecondAgent() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
          ShadowBackupDataInput.throwInNextHeaderRead();
  
          runTask(task);
  
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
      }
  
      @Test
      public void testRunTask_whenReadingBackupDataThrows_cleansUpAndRevertsTask() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentsWithData(PACKAGE_1, PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
          ShadowBackupDataInput.throwInNextHeaderRead();
  
          runTask(task);
  
          assertCleansUpFiles(mTransport, PACKAGE_2);
          assertTaskReverted(transportMock, PACKAGE_1, PACKAGE_2);
      }
  
      @Test
      public void testRunTask_whenMarkCancelDuringAgentOnBackup_cleansUpFiles() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                      runInWorkerThread(task::markCancel);
                  });
  
          runTask(task);
  
          assertCleansUpFiles(mTransport, PACKAGE_1);
      }
  
      @Test
      public void
              testRunTask_whenMarkCancelDuringFirstAgentOnBackup_doesNotCallTransportAfterWaitCancel()
                      throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          setUpAgentsWithData(PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                      runInWorkerThread(task::markCancel);
                  });
  
          ConditionVariable taskFinished = runTaskAsync(task);
  
          verifyAndUnblockAgentCalls(2);
          task.waitCancel();
          reset(transportMock.transport);
          taskFinished.block();
          verifyZeroInteractions(transportMock.transport);
      }
  
      @Test
      public void testRunTask_whenMarkCancelDuringAgentOnBackup_doesNotCallTransportForPackage()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                      runInWorkerThread(task::markCancel);
                  });
  
          ConditionVariable taskFinished = runTaskAsync(task);
  
          verifyAndUnblockAgentCalls(2);
          taskFinished.block();
          // For PM
          verify(transportMock.transport, times(1)).finishBackup();
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_whenMarkCancelDuringTransportPerformBackup_callsTransportForPackage()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenAnswer(
                          invocation -> {
                              runInWorkerThread(task::markCancel);
                              return BackupTransport.TRANSPORT_OK;
                          });
  
          ConditionVariable taskFinished = runTaskAsync(task);
  
          verifyAndUnblockAgentCalls(2);
          taskFinished.block();
          InOrder inOrder = inOrder(transportMock.transport);
          inOrder.verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
          inOrder.verify(transportMock.transport).finishBackup();
      }
  
      @Test
      public void
              testRunTask_whenMarkCancelDuringSecondAgentOnBackup_callsTransportForFirstPackageButNotForSecond()
                      throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          AgentMock agentMock = setUpAgent(PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                      runInWorkerThread(task::markCancel);
                  });
  
          ConditionVariable taskFinished = runTaskAsync(task);
  
          verifyAndUnblockAgentCalls(3);
          taskFinished.block();
          InOrder inOrder = inOrder(transportMock.transport);
          inOrder.verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
          inOrder.verify(transportMock.transport).finishBackup();
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
      }
  
      @Test
      public void
              testRunTask_whenMarkCancelDuringTransportPerformBackupForFirstPackage_callsTransportForFirstPackageButNotForSecond()
                      throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentsWithData(PACKAGE_1, PACKAGE_2);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
          when(transportMock.transport.performBackup(
                          argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                  .thenAnswer(
                          invocation -> {
                              runInWorkerThread(task::markCancel);
                              return BackupTransport.TRANSPORT_OK;
                          });
  
          ConditionVariable taskFinished = runTaskAsync(task);
  
          verifyAndUnblockAgentCalls(2);
          taskFinished.block();
          InOrder inOrder = inOrder(transportMock.transport);
          inOrder.verify(transportMock.transport)
                  .performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
          inOrder.verify(transportMock.transport).finishBackup();
          verify(transportMock.transport, never())
                  .performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt());
      }
  
      @Test
      public void testRunTask_afterMarkCancel_doesNotCallAgentOrTransport() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          AgentMock agentMock = setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          task.markCancel();
  
          runTask(task);
  
          verify(agentMock.agent, never()).onBackup(any(), any(), any());
          verify(transportMock.transport, never()).performBackup(any(), any(), anyInt());
          verify(transportMock.transport, never()).finishBackup();
      }
  
      @Test
      public void testWaitCancel_afterCancelledTaskFinished_returns() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          task.markCancel();
          runTask(task);
  
          task.waitCancel();
      }
  
      @Test
      public void testWaitCancel_whenMarkCancelDuringAgentOnBackup_unregistersTask()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          AgentMock agentMock = setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          agentOnBackupDo(
                  agentMock,
                  (oldState, dataOutput, newState) -> {
                      writeData(dataOutput, "key", "data".getBytes());
                      writeState(newState, "newState".getBytes());
                      runInWorkerThread(task::markCancel);
                  });
          ConditionVariable taskFinished = runTaskAsync(task);
          verifyAndUnblockAgentCalls(1);
          boolean backupInProgressDuringBackup = mBackupManagerService.isBackupOperationInProgress();
          assertThat(backupInProgressDuringBackup).isTrue();
          verifyAndUnblockAgentCalls(1);
  
          task.waitCancel();
  
          boolean backupInProgressAfterWaitCancel =
                  mBackupManagerService.isBackupOperationInProgress();
          assertThat(backupInProgressDuringBackup).isTrue();
          assertThat(backupInProgressAfterWaitCancel).isFalse();
          taskFinished.block();
      }
  
      @Test
      public void testMarkCancel_afterTaskFinished_returns() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
          runTask(task);
  
          task.markCancel();
      }
  
      @Test
      public void testHandleCancel_callsMarkCancelAndWaitCancel() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = spy(createKeyValueBackupTask(transportMock, PACKAGE_1));
          doNothing().when(task).waitCancel();
  
          task.handleCancel(true);
  
          InOrder inOrder = inOrder(task);
          inOrder.verify(task).markCancel();
          inOrder.verify(task).waitCancel();
      }
  
      @Test
      public void testHandleCancel_whenCancelAllFalse_throws() throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          setUpAgentWithData(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
  
          expectThrows(IllegalArgumentException.class, () -> task.handleCancel(false));
      }
  
      /**
       * Do not update backup token if no data was moved.
       */
      @Test
      public void testRunTask_whenNoDataToBackupOnFirstBackup_doesNotUpdateCurrentToken()
              throws Exception {
          TransportMock transportMock = setUpInitializedTransport(mTransport);
          mBackupManagerService.setCurrentToken(0L);
          when(transportMock.transport.getCurrentRestoreSet()).thenReturn(1234L);
          // Set up agent with no data.
          setUpAgent(PACKAGE_1);
          KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
  
          runTask(task);
  
          assertThat(mBackupManagerService.getCurrentToken()).isEqualTo(0L);
      }
  
      private void runTask(KeyValueBackupTask task) {
          // Pretend we are not on the main-thread to prevent RemoteCall from complaining
          mShadowMainLooper.setCurrentThread(false);
          task.run();
          mShadowMainLooper.reset();
          assertTaskPostConditions();
      }
  
      private ConditionVariable runTaskAsync(KeyValueBackupTask task) {
          return runInWorkerThreadAsync(task::run);
      }
  
      private static ConditionVariable runInWorkerThreadAsync(ThrowingRunnable runnable) {
          ConditionVariable finished = new ConditionVariable(false);
          new Thread(
                          () -> {
                              uncheck(runnable);
                              finished.open();
                          },
                          "test-worker-thread")
                  .start();
          return finished;
      }
  
      private static void runInWorkerThread(ThrowingRunnable runnable) {
          runInWorkerThreadAsync(runnable).block();
      }
  
      /**
       * If you have kicked-off the task with {@link #runTaskAsync(KeyValueBackupTask)}, call this to
       * unblock the task thread that will be waiting for the agent's {@link
       * IBackupAgent#doBackup(ParcelFileDescriptor, ParcelFileDescriptor, ParcelFileDescriptor, long,
       * IBackupCallback, int)}.
       *
       * @param times The number of {@link IBackupAgent#doBackup(ParcelFileDescriptor,
       *     ParcelFileDescriptor, ParcelFileDescriptor, long, IBackupCallback, int)} calls. Remember
       *     to count PM calls.
       */
      private void verifyAndUnblockAgentCalls(int times)
              throws InterruptedException, TimeoutException {
          // HACK: IBackupAgent.doBackup() posts a runnable to the front of the main-thread queue and
          // immediately waits for its execution. In Robolectric, if we are in the main-thread this
          // runnable is executed inline (this is called unpaused looper), that's why when we run the
          // task in the main-thread (runTask() as opposed to runTaskAsync()) we don't need to call
          // this method. However, if we are not in the main-thread nobody executes the runnable for
          // us, thus IBackupAgent code will be stuck waiting for someone to execute the runnable.
          // This method waits for that *specific* runnable, identifying it via class name, and then
          // idles the main looper (for 0 seconds because it's posted at the front of the queue),
          // which executes the method.
          for (int i = 0; i < times; i++) {
              waitUntil(() -> messagesInLooper(mMainLooper, this::isSharedPrefsSynchronizer) > 0);
              mShadowMainLooper.idle();
          }
      }
  
      private boolean isSharedPrefsSynchronizer(@Nullable Message message) {
          String className = BACKUP_AGENT_SHARED_PREFS_SYNCHRONIZER_CLASS;
          return message != null
                  && message.getCallback() != null
                  && className.equals(message.getCallback().getClass().getName());
      }
  
      private TransportMock setUpTransport(TransportData transport) throws Exception {
          TransportMock transportMock =
                  TransportTestUtils.setUpTransport(mTransportManager, transport);
          Files.createDirectories(getStateDirectory(transport));
          return transportMock;
      }
  
      /** Sets up the transport and writes a PM state file in the transport state directory. */
      private TransportMock setUpInitializedTransport(TransportData transport) throws Exception {
          TransportMock transportMock = setUpTransport(transport);
          createPmStateFile(transport);
          return transportMock;
      }
  
      private Path getStateDirectory(TransportData transport) {
          return mBaseStateDir.toPath().resolve(transport.transportDirName);
      }
  
      private Path getStateFile(TransportData transport, PackageData packageData) {
          return getStateDirectory(transport).resolve(packageData.packageName);
      }
  
      private Path getTemporaryStateFile(TransportData transport, PackageData packageData) {
          return getStateDirectory(transport)
                  .resolve(packageData.packageName + KeyValueBackupTask.NEW_STATE_FILE_SUFFIX);
      }
  
      private Path getStagingDirectory() {
          return mDataDir.toPath();
      }
  
      private Path getStagingFile(PackageData packageData) {
          return getStagingDirectory()
                  .resolve(packageData.packageName + KeyValueBackupTask.STAGING_FILE_SUFFIX);
      }
  
      private List<AgentMock> setUpAgents(PackageData... packageNames) {
          return Stream.of(packageNames).map(this::setUpAgent).collect(toList());
      }
  
      private AgentMock setUpAgent(PackageData packageData) {
          try {
              String packageName = packageData.packageName;
              mPackageManager.setApplicationEnabledSetting(
                      packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
              PackageInfo packageInfo = getPackageInfo(packageData);
              mShadowPackageManager.installPackage(packageInfo);
              ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
              mContext.sendBroadcast(getPackageAddedIntent(packageData));
              // Run the backup looper because on the receiver we post MSG_SCHEDULE_BACKUP_PACKAGE
              mShadowBackupLooper.runToEndOfTasks();
              BackupAgent backupAgent = spy(BackupAgent.class);
              IBackupAgent backupAgentBinder =
                      spy(IBackupAgent.Stub.asInterface(backupAgent.onBind()));
              // Don't crash our only process (in production code this would crash the app, not us)
              doNothing().when(backupAgentBinder).fail(any());
              if (packageData.available) {
                  doReturn(backupAgentBinder)
                          .when(mBackupManagerService)
                          .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt());
              } else {
                  doReturn(null)
                          .when(mBackupManagerService)
                          .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt());
              }
              return new AgentMock(backupAgentBinder, backupAgent);
          } catch (RemoteException e) {
              // Never happens, compiler happy
              throw new AssertionError(e);
          }
      }
  
      private PackageInfo getPackageInfo(PackageData packageData) {
          PackageInfo packageInfo = new PackageInfo();
          packageInfo.packageName = packageData.packageName;
          packageInfo.applicationInfo = new ApplicationInfo();
          packageInfo.applicationInfo.uid = packageData.uid;
          packageInfo.applicationInfo.flags = packageData.flags();
          packageInfo.applicationInfo.backupAgentName = packageData.agentName;
          packageInfo.applicationInfo.packageName = packageData.packageName;
          return packageInfo;
      }
  
      private Intent getPackageAddedIntent(PackageData packageData) {
          Intent intent =
                  new Intent(
                          Intent.ACTION_PACKAGE_ADDED,
                          Uri.parse("package:" + packageData.packageName));
          intent.putExtra(Intent.EXTRA_UID, packageData.uid);
          intent.putExtra(Intent.EXTRA_REPLACING, false);
          intent.putExtra(Intent.EXTRA_USER_HANDLE, 0);
          return intent;
      }
  
      private List<AgentMock> setUpAgentsWithData(PackageData... packages) {
          return Stream.of(packages).map(this::setUpAgentWithData).collect(toList());
      }
  
      private AgentMock setUpAgentWithData(PackageData packageData) {
          AgentMock agentMock = setUpAgent(packageData);
          String packageName = packageData.packageName;
          uncheck(
                  () ->
                          agentOnBackupDo(
                                  agentMock,
                                  (oldState, dataOutput, newState) -> {
                                      writeData(dataOutput, "key", ("data" + packageName).getBytes());
                                      writeState(newState, ("state" + packageName).getBytes());
                                  }));
          return agentMock;
      }
  
      private KeyValueBackupTask createKeyValueBackupTask(
              TransportMock transportMock, PackageData... packages) {
          return createKeyValueBackupTask(transportMock, false, packages);
      }
  
      private KeyValueBackupTask createKeyValueBackupTask(
              TransportMock transportMock, boolean nonIncremental, PackageData... packages) {
          List<String> queue =
                  Stream.of(packages).map(packageData -> packageData.packageName).collect(toList());
          mBackupManagerService.getPendingBackups().clear();
          // mOldJournal is a mock, but it would be the value returned by BMS.getJournal() now
          mBackupManagerService.setJournal(null);
          mWakeLock.acquire();
          KeyValueBackupTask task =
                  new KeyValueBackupTask(
                          mBackupManagerService,
                          transportMock.transportClient,
                          transportMock.transportData.transportDirName,
                          queue,
                          mOldJournal,
                          mReporter,
                          mListener,
                          emptyList(),
                          /* userInitiated */ false,
                          nonIncremental);
          mBackupManager.setUp(mBackupHandler, task);
          return task;
      }
  
      private PackageManagerBackupAgent createPmAgent() {
          PackageManagerBackupAgent pmAgent =
                  new PackageManagerBackupAgent(mApplication.getPackageManager(), USER_ID);
          pmAgent.attach(mApplication);
          pmAgent.onCreate();
          return pmAgent;
      }
  
      /**
       * Returns an implementation of PackageManagerBackupAgent that throws RuntimeException in {@link
       * BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
       */
      private PackageManagerBackupAgent createThrowingPmAgent(RuntimeException exception) {
          PackageManagerBackupAgent pmAgent =
                  new ThrowingPackageManagerBackupAgent(mApplication.getPackageManager(), exception);
          pmAgent.attach(mApplication);
          pmAgent.onCreate();
          return pmAgent;
      }
  
      /** Matches {@link PackageInfo} whose package name is {@code packageData.packageName}. */
      private static ArgumentMatcher<PackageInfo> packageInfo(PackageData packageData) {
          // We have to test for packageInfo nulity because of Mockito's own stubbing with argThat().
          // E.g. if you do:
          //
          //   1. when(object.method(argThat(str -> str.equals("foo")))).thenReturn(0)
          //   2. when(object.method(argThat(str -> str.equals("bar")))).thenReturn(2)
          //
          // The second line will throw NPE because it will call lambda 1 with null, since argThat()
          // returns null. So we guard against that by checking for null.
          return packageInfo ->
                  packageInfo != null && packageData.packageName.equals(packageInfo.packageName);
      }
  
      /** Matches {@link ApplicationInfo} whose package name is {@code packageData.packageName}. */
      private static ArgumentMatcher<ApplicationInfo> applicationInfo(PackageData packageData) {
          return applicationInfo ->
                  applicationInfo != null
                          && packageData.packageName.equals(applicationInfo.packageName);
      }
  
      private static ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
          return dataOutput -> dataOutput.getTransportFlags() == flags;
      }
  
      private static void writeData(BackupDataOutput dataOutput, String key, byte[] data)
              throws IOException {
          dataOutput.writeEntityHeader(key, data.length);
          dataOutput.writeEntityData(data, data.length);
      }
  
      private static void writeState(ParcelFileDescriptor newState, byte[] state) throws IOException {
          OutputStream outputStream = new FileOutputStream(newState.getFileDescriptor());
          outputStream.write(state);
          outputStream.flush();
      }
  
      /**
       * This is to prevent the following:
       *
       * <ul>
       *   <li>The transport being initialized with {@link IBackupTransport#initializeDevice()}
       *   <li>{@link UserBackupManagerService#resetBackupState(File)} being called, which will:
       *       <ul>
       *         <li>Reset processed packages journal.
       *         <li>Reset current token to 0.
       *         <li>Delete state files.
       *         <li>Mark data changed for every key-value participant.
       *       </ul>
       * </ul>
       */
      private void createPmStateFile() throws IOException {
          createPmStateFile(mTransport);
      }
  
      /** @see #createPmStateFile() */
      private void createPmStateFile(TransportData transport) throws IOException {
          Files.write(getStateFile(transport, PM_PACKAGE), "pmState".getBytes());
      }
  
      /**
       * Forces transport initialization and call to {@link
       * UserBackupManagerService#resetBackupState(File)}
       */
      private void deletePmStateFile() throws IOException {
          Files.deleteIfExists(getStateFile(mTransport, PM_PACKAGE));
      }
  
      /**
       * Implements {@code function} for {@link BackupAgent#onBackup(ParcelFileDescriptor,
       * BackupDataOutput, ParcelFileDescriptor)} of {@code agentMock} and populates {@link
       * AgentMock#oldState}.
       *
       * <p>Note that for throwing agents this will simulate a local agent (the exception will be
       * thrown in our stack), use {@link #remoteAgentOnBackupThrows(AgentMock, BackupAgentOnBackup)}
       * if you want to simulate a remote agent.
       */
      private static void agentOnBackupDo(AgentMock agentMock, BackupAgentOnBackup function)
              throws Exception {
          agentOnBackupDo(
                  agentMock.agent,
                  (oldState, dataOutput, newState) -> {
                      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                      transferStreamedData(
                              new FileInputStream(oldState.getFileDescriptor()), outputStream);
                      agentMock.oldState = outputStream.toByteArray();
                      agentMock.oldStateHistory.add(agentMock.oldState);
                      function.onBackup(oldState, dataOutput, newState);
                  });
      }
  
      /**
       * Implements {@code function} for {@link BackupAgent#onBackup(ParcelFileDescriptor,
       * BackupDataOutput, ParcelFileDescriptor)} of {@code agentMock}.
       *
       * @see #agentOnBackupDo(AgentMock, BackupAgentOnBackup)
       * @see #remoteAgentOnBackupThrows(AgentMock, BackupAgentOnBackup)
       */
      private static void agentOnBackupDo(BackupAgent backupAgent, BackupAgentOnBackup function)
              throws IOException {
          doAnswer(function).when(backupAgent).onBackup(any(), any(), any());
      }
  
      /**
       * Use this method to simulate a remote agent throwing. We catch the exception thrown, thus
       * simulating a one-way call. It also populates {@link AgentMock#oldState}.
       *
       * @param agentMock The Agent mock.
       * @param function A function that throws, otherwise the test will fail.
       */
      // TODO: Remove when RemoteCall spins up a dedicated thread for calls
      private static void remoteAgentOnBackupThrows(AgentMock agentMock, BackupAgentOnBackup function)
              throws Exception {
          agentOnBackupDo(agentMock, function);
          doAnswer(
                          invocation -> {
                              try {
                                  invocation.callRealMethod();
                                  fail("Agent method expected to throw");
                              } catch (RuntimeException e) {
                                  // This silences the exception just like a one-way call would, the
                                  // normal completion via IBackupCallback binder still happens, check
                                  // finally() block of IBackupAgent.doBackup().
                              }
                              return null;
                          })
                  .when(agentMock.agentBinder)
                  .doBackup(any(), any(), any(), anyLong(), any(), anyInt());
      }
  
      /**
       * Returns an {@link Answer} that can be used for mocking {@link
       * IBackupTransport#performBackup(PackageInfo, ParcelFileDescriptor, int)} that copies the
       * backup data received to {@code backupDataPath} and returns {@code result}.
       */
      private static Answer<Integer> copyBackupDataAndReturn(Path backupDataPath, int result) {
          return invocation -> {
              ParcelFileDescriptor backupDataParcelFd = invocation.getArgument(1);
              FileDescriptor backupDataFd = backupDataParcelFd.getFileDescriptor();
              Files.copy(new FileInputStream(backupDataFd), backupDataPath, REPLACE_EXISTING);
              backupDataParcelFd.close();
              return result;
          };
      }
  
      /**
       * Same as {@link #copyBackupDataAndReturn(Path, int)}} with {@code result =
       * BackupTransport.TRANSPORT_OK}.
       */
      private static Answer<Integer> copyBackupDataTo(Path backupDataPath) {
          return copyBackupDataAndReturn(backupDataPath, BackupTransport.TRANSPORT_OK);
      }
  
      private Path createTemporaryFile() throws IOException {
          return Files.createTempFile(mContext.getCacheDir().toPath(), "backup", ".tmp");
      }
  
      private static IterableSubject assertDirectory(Path directory) throws IOException {
          return assertThat(oneTimeIterable(Files.newDirectoryStream(directory).iterator()))
                  .named("directory " + directory);
      }
  
      private static void assertJournalDoesNotContain(
              @Nullable DataChangedJournal journal, String packageName) throws IOException {
          List<String> packages = (journal == null) ? emptyList() : journal.getPackages();
          assertThat(packages).doesNotContain(packageName);
      }
  
      private void assertTaskReverted(TransportMock transportMock, PackageData... packages)
              throws RemoteException, IOException {
          verify(transportMock.transport).requestBackupTime();
          assertBackupPendingFor(packages);
          assertThat(KeyValueBackupJob.isScheduled(mBackupManagerService.getUserId())).isTrue();
      }
  
      private void assertBackupPendingFor(PackageData... packages) throws IOException {
          for (PackageData packageData : packages) {
              String packageName = packageData.packageName;
              // We verify the current journal, NOT the old one passed to KeyValueBackupTask
              // constructor
              assertThat(mBackupManagerService.getJournal().getPackages()).contains(packageName);
              assertThat(mBackupManagerService.getPendingBackups()).containsKey(packageName);
          }
      }
  
      private void assertBackupNotPendingFor(PackageData... packages) throws IOException {
          for (PackageData packageData : packages) {
              String packageName = packageData.packageName;
              // We verify the current journal, NOT the old one passed to KeyValueBackupTask
              // constructor
              assertJournalDoesNotContain(mBackupManagerService.getJournal(), packageName);
              assertThat(mBackupManagerService.getPendingBackups()).doesNotContainKey(packageName);
              // Also verifying BMS is never called since for some cases the package wouldn't be
              // pending for other reasons (for example it's not eligible for backup). Regardless of
              // these reasons, we shouldn't mark them as pending backup (call dataChangedImpl()).
              verify(mBackupManagerService, never()).dataChangedImpl(packageName);
          }
      }
  
      private void assertDataHasKeyValue(BackupDataInput backupData, String key, byte[] value)
              throws IOException {
          assertThat(backupData.readNextHeader()).isTrue();
          assertThat(backupData.getKey()).isEqualTo(key);
          int size = backupData.getDataSize();
          byte[] data1 = new byte[size];
          backupData.readEntityData(data1, 0, size);
          assertThat(data1).isEqualTo(value);
      }
  
      private void assertCleansUpFilesAndAgent(TransportData transport, PackageData packageData) {
          assertCleansUpFiles(transport, packageData);
          verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(packageData)));
      }
  
      private void assertCleansUpFiles(TransportData transport, PackageData packageData) {
          assertThat(Files.exists(getTemporaryStateFile(transport, packageData))).isFalse();
          assertThat(Files.exists(getStagingFile(packageData))).isFalse();
      }
  
      /**
       * Put conditions that should *always* be true after task execution.
       *
       * <p>Note: We should generally NOT do this. For every different set of pre-conditions that
       * result in different code-paths being executed there should be one test method verifying these
       * post-conditions. Since there were a couple of methods here already and these post-conditions
       * are pretty serious to be neglected it was decided to over-verify in this case.
       */
      private void assertTaskPostConditions() {
          assertThat(mWakeLock.isHeld()).isFalse();
      }
  
      @FunctionalInterface
      private interface BackupAgentOnBackup extends Answer<Void> {
          void onBackup(
                  ParcelFileDescriptor oldState,
                  BackupDataOutput dataOutput,
                  ParcelFileDescriptor newState)
                  throws IOException;
  
          @Override
          default Void answer(InvocationOnMock invocation) throws Throwable {
              onBackup(
                      invocation.getArgument(0),
                      invocation.getArgument(1),
                      invocation.getArgument(2));
              return null;
          }
      }
  
      private static class AgentMock {
          private final IBackupAgent agentBinder;
          private final BackupAgent agent;
          private final List<byte[]> oldStateHistory = new ArrayList<>();
          private byte[] oldState;
  
          private AgentMock(IBackupAgent agentBinder, BackupAgent agent) {
              this.agentBinder = agentBinder;
              this.agent = agent;
          }
      }
  
      private abstract static class FakeIBackupManager extends IBackupManager.Stub {
          private Handler mBackupHandler;
          private BackupRestoreTask mTask;
  
          public FakeIBackupManager() {}
  
          private void setUp(Handler backupHandler, BackupRestoreTask task) {
              mBackupHandler = backupHandler;
              mTask = task;
          }
  
          @Override
          public void opComplete(int token, long result) throws RemoteException {
              assertThat(mTask).isNotNull();
              Message message =
                      mBackupHandler.obtainMessage(
                              BackupHandler.MSG_OP_COMPLETE, Pair.create(mTask, result));
              mBackupHandler.sendMessage(message);
          }
      }
  
      private static class ThrowingPackageManagerBackupAgent extends PackageManagerBackupAgent {
          private final RuntimeException mException;
  
          ThrowingPackageManagerBackupAgent(
                  PackageManager packageManager, RuntimeException exception) {
              super(packageManager, USER_ID);
              mException = exception;
          }
  
          @Override
          public void onBackup(
                  ParcelFileDescriptor oldState,
                  BackupDataOutput data,
                  ParcelFileDescriptor newState) {
              throw mException;
          }
      }
  }
  