Merge "Fix state deletion for transient backup issues." into rvc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
2170ba0f9f
@@ -649,16 +649,33 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
|
|||||||
mReporter.onStartPackageBackup(PM_PACKAGE);
|
mReporter.onStartPackageBackup(PM_PACKAGE);
|
||||||
mCurrentPackage = new PackageInfo();
|
mCurrentPackage = new PackageInfo();
|
||||||
mCurrentPackage.packageName = PM_PACKAGE;
|
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 {
|
try {
|
||||||
extractPmAgentData(mCurrentPackage);
|
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);
|
int status = sendDataToTransport(mCurrentPackage);
|
||||||
cleanUpAgentForTransportStatus(status);
|
cleanUpAgentForTransportStatus(status);
|
||||||
} catch (AgentException | TaskException e) {
|
} catch (AgentException | TaskException e) {
|
||||||
mReporter.onExtractPmAgentDataError(e);
|
mReporter.onExtractPmAgentDataError(e);
|
||||||
cleanUpAgentForError(e);
|
cleanUpAgentForError(e);
|
||||||
// PM agent failure is task failure.
|
if (e instanceof TaskException) {
|
||||||
throw TaskException.stateCompromised(e);
|
throw (TaskException) e;
|
||||||
|
} else {
|
||||||
|
throw TaskException.stateCompromised(e); // PM agent failure is task failure.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ import com.android.server.testing.shadows.ShadowBackupDataOutput;
|
|||||||
import com.android.server.testing.shadows.ShadowEventLog;
|
import com.android.server.testing.shadows.ShadowEventLog;
|
||||||
import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
|
import com.android.server.testing.shadows.ShadowSystemServiceRegistry;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.truth.IterableSubject;
|
import com.google.common.truth.IterableSubject;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -1910,7 +1911,8 @@ public class KeyValueBackupTaskTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRunTask_whenTransportReturnsError_updatesFilesAndCleansUp() throws Exception {
|
public void testRunTask_whenTransportReturnsErrorForGenericPackage_updatesFilesAndCleansUp()
|
||||||
|
throws Exception {
|
||||||
TransportMock transportMock = setUpInitializedTransport(mTransport);
|
TransportMock transportMock = setUpInitializedTransport(mTransport);
|
||||||
when(transportMock.transport.performBackup(
|
when(transportMock.transport.performBackup(
|
||||||
argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
|
argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
|
||||||
@@ -1926,6 +1928,39 @@ public class KeyValueBackupTaskTest {
|
|||||||
assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
|
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
|
@Test
|
||||||
public void testRunTask_whenTransportGetBackupQuotaThrowsForPm() throws Exception {
|
public void testRunTask_whenTransportGetBackupQuotaThrowsForPm() throws Exception {
|
||||||
TransportMock transportMock = setUpInitializedTransport(mTransport);
|
TransportMock transportMock = setUpInitializedTransport(mTransport);
|
||||||
@@ -2707,21 +2742,29 @@ public class KeyValueBackupTaskTest {
|
|||||||
* </ul>
|
* </ul>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
private void createPmStateFile() throws IOException {
|
private Path createPmStateFile() throws IOException {
|
||||||
createPmStateFile(mTransport);
|
return createPmStateFile("pmState".getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see #createPmStateFile() */
|
private Path createPmStateFile(byte[] bytes) throws IOException {
|
||||||
private void createPmStateFile(TransportData transport) throws IOException {
|
return createPmStateFile(bytes, mTransport);
|
||||||
Files.write(getStateFile(transport, PM_PACKAGE), "pmState".getBytes());
|
}
|
||||||
|
|
||||||
|
private Path createPmStateFile(TransportData transport) throws IOException {
|
||||||
|
return createPmStateFile("pmState".getBytes(), mTransport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @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
|
* Forces transport initialization and call to {@link
|
||||||
* UserBackupManagerService#resetBackupState(File)}
|
* UserBackupManagerService#resetBackupState(File)}
|
||||||
*/
|
*/
|
||||||
private void deletePmStateFile() throws IOException {
|
private boolean deletePmStateFile() throws IOException {
|
||||||
Files.deleteIfExists(getStateFile(mTransport, PM_PACKAGE));
|
return Files.deleteIfExists(getStateFile(mTransport, PM_PACKAGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user