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

Commit 2170ba0f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix state deletion for transient backup issues." into rvc-qpr-dev

parents a24cc034 723f5f36
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
@@ -649,16 +649,33 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
        mReporter.onStartPackageBackup(PM_PACKAGE);
        mCurrentPackage = new PackageInfo();
        mCurrentPackage.packageName = PM_PACKAGE;

        try {
            // If we can't even extractPmAgentData(), then we treat the local state as
            // compromised, just in case. This means that we will clear data and will
            // start from a clean slate in the next attempt. It's not clear whether that's
            // the right thing to do, but matches what we have historically done.
            try {
                extractPmAgentData(mCurrentPackage);
            } catch (TaskException e) {
                throw TaskException.stateCompromised(e); // force stateCompromised
            }
            // During sendDataToTransport, we generally trust any thrown TaskException
            // about whether stateCompromised because those are likely transient;
            // clearing state for those would have the potential to lead to cascading
            // failures, as discussed in http://b/144030477.
            // For specific status codes (e.g. TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED),
            // cleanUpAgentForTransportStatus() or theoretically handleTransportStatus()
            // still have the opportunity to perform additional clean-up tasks.
            int status = sendDataToTransport(mCurrentPackage);
            cleanUpAgentForTransportStatus(status);
        } catch (AgentException | TaskException e) {
            mReporter.onExtractPmAgentDataError(e);
            cleanUpAgentForError(e);
            // PM agent failure is task failure.
            throw TaskException.stateCompromised(e);
            if (e instanceof TaskException) {
                throw (TaskException) e;
            } else {
                throw TaskException.stateCompromised(e); // PM agent failure is task failure.
            }
        }
    }

+51 −8
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ import com.android.server.testing.shadows.ShadowBackupDataOutput;
import com.android.server.testing.shadows.ShadowEventLog;
import com.android.server.testing.shadows.ShadowSystemServiceRegistry;

import com.google.common.base.Charsets;
import com.google.common.truth.IterableSubject;

import org.junit.After;
@@ -1910,7 +1911,8 @@ public class KeyValueBackupTaskTest {
    }

    @Test
    public void testRunTask_whenTransportReturnsError_updatesFilesAndCleansUp() throws Exception {
    public void testRunTask_whenTransportReturnsErrorForGenericPackage_updatesFilesAndCleansUp()
            throws Exception {
        TransportMock transportMock = setUpInitializedTransport(mTransport);
        when(transportMock.transport.performBackup(
                        argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
@@ -1926,6 +1928,39 @@ public class KeyValueBackupTaskTest {
        assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
    }

    /**
     * Checks that TRANSPORT_ERROR during @pm@ backup keeps the state file untouched.
     * http://b/144030477
     */
    @Test
    public void testRunTask_whenTransportReturnsErrorForPm_updatesFilesAndCleansUp()
            throws Exception {
        // TODO(tobiast): Refactor this method to share code with
        //  testRunTask_whenTransportReturnsErrorForGenericPackage_updatesFilesAndCleansUp
        // See patchset 7 of http://ag/11762961
        final PackageData packageData = PM_PACKAGE;
        TransportMock transportMock = setUpInitializedTransport(mTransport);
        when(transportMock.transport.performBackup(
                argThat(packageInfo(packageData)), any(), anyInt()))
                .thenReturn(BackupTransport.TRANSPORT_ERROR);

        byte[] pmStateBytes = "fake @pm@ state for testing".getBytes(Charsets.UTF_8);

        Path pmStatePath = createPmStateFile(pmStateBytes.clone());
        PackageManagerBackupAgent pmAgent = spy(createPmAgent());
        KeyValueBackupTask task = createKeyValueBackupTask(transportMock, packageData);
        runTask(task);
        verify(pmAgent, never()).onBackup(any(), any(), any());

        assertThat(Files.readAllBytes(pmStatePath)).isEqualTo(pmStateBytes.clone());

        boolean existed = deletePmStateFile();
        assertThat(existed).isTrue();
        // unbindAgent() is skipped for @pm@. Comment in KeyValueBackupTask.java:
        // "For PM metadata (for which applicationInfo is null) there is no agent-bound state."
        assertCleansUpFiles(mTransport, packageData);
    }

    @Test
    public void testRunTask_whenTransportGetBackupQuotaThrowsForPm() throws Exception {
        TransportMock transportMock = setUpInitializedTransport(mTransport);
@@ -2707,21 +2742,29 @@ public class KeyValueBackupTaskTest {
     *       </ul>
     * </ul>
     */
    private void createPmStateFile() throws IOException {
        createPmStateFile(mTransport);
    private Path createPmStateFile() throws IOException {
        return createPmStateFile("pmState".getBytes());
    }

    private Path createPmStateFile(byte[] bytes) throws IOException {
        return createPmStateFile(bytes, mTransport);
    }

    private Path createPmStateFile(TransportData transport) throws IOException {
        return createPmStateFile("pmState".getBytes(), mTransport);
    }

    /** @see #createPmStateFile() */
    private void createPmStateFile(TransportData transport) throws IOException {
        Files.write(getStateFile(transport, PM_PACKAGE), "pmState".getBytes());
    /** @see #createPmStateFile(byte[]) */
    private Path createPmStateFile(byte[] bytes, TransportData transport) throws IOException {
        return Files.write(getStateFile(transport, PM_PACKAGE), bytes);
    }

    /**
     * Forces transport initialization and call to {@link
     * UserBackupManagerService#resetBackupState(File)}
     */
    private void deletePmStateFile() throws IOException {
        Files.deleteIfExists(getStateFile(mTransport, PM_PACKAGE));
    private boolean deletePmStateFile() throws IOException {
        return Files.deleteIfExists(getStateFile(mTransport, PM_PACKAGE));
    }

    /**