blob: 47564763bac96d92d4cbee48ed01bf8e72be135a [file] [log] [blame]
package com.android.server.testing.shadows;
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Shadow for {@link FullBackup}. Used to emulate the native method {@link
* FullBackup#backupToTar(String, String, String, String, String, FullBackupDataOutput)}. Relies on
* the shadow {@link ShadowBackupDataOutput}, which must be included in tests that use this shadow.
*/
@Implements(FullBackup.class)
public class ShadowFullBackup {
/**
* Reads data from the specified file at {@code path} and writes it to the {@code output}. Does
* not match the native implementation, and only partially simulates TAR format. Used solely for
* passing backup data for testing purposes.
*
* <p>Note: Only handles the {@code path} denoting a file and not a directory like the real
* implementation.
*/
@Implementation
protected static int backupToTar(
String packageName,
String domain,
String linkdomain,
String rootpath,
String path,
FullBackupDataOutput output) {
BackupDataOutput backupDataOutput = output.getData();
try {
Path file = Paths.get(path);
byte[] data = Files.readAllBytes(file);
backupDataOutput.writeEntityHeader("key", data.length);
// Partially simulate TAR header (not all fields included). We use a 512 byte block for
// the header to follow the TAR convention and to have a consistent size block to help
// with separating the header from the data.
ByteBuffer tarBlock = ByteBuffer.wrap(new byte[512]);
String tarPath = "apps/" + packageName + (domain == null ? "" : "/" + domain) + path;
tarBlock.put(tarPath.getBytes()); // file path
tarBlock.putInt(0x1ff); // file mode
tarBlock.putLong(Files.size(file)); // file size
tarBlock.putLong(Files.getLastModifiedTime(file).toMillis()); // last modified time
tarBlock.putInt(0); // file type
// Write TAR header directly to the BackupDataOutput's output stream.
ShadowBackupDataOutput shadowBackupDataOutput = Shadow.extract(backupDataOutput);
ObjectOutputStream outputStream = shadowBackupDataOutput.getOutputStream();
outputStream.write(tarBlock.array());
outputStream.flush();
backupDataOutput.writeEntityData(data, data.length);
} catch (IOException e) {
throw new AssertionError(e);
}
return 0;
}
}