Fix transport encryption
Prior to this commit, some of the application data was not included during encryption. This is a breaking change, any backups made prior to this commit can no longer be restored. 1. Encrypt 'full' backup data. 2. Increase number of key generation iterations to 32767. 3. Change cipher to 'AES/CBC/PKCS5Padding'.
This commit is contained in:
parent
b16fcf5d87
commit
04543a1014
7 changed files with 254 additions and 168 deletions
|
@ -16,12 +16,13 @@ public class CipherUtil {
|
|||
/**
|
||||
* The cipher algorithm.
|
||||
*/
|
||||
public static final String CIPHER_ALGORITHM = "AES/CFB/PKCS5Padding";
|
||||
public static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
|
||||
|
||||
/**.
|
||||
/**
|
||||
* .
|
||||
* Encrypts the given payload using the provided secret key.
|
||||
*
|
||||
* @param payload The payload.
|
||||
* @param payload The payload.
|
||||
* @param secretKey The secret key.
|
||||
* @param iv The initialization vector.
|
||||
*/
|
||||
|
@ -29,9 +30,22 @@ public class CipherUtil {
|
|||
NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException,
|
||||
InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
|
||||
return startEncrypt(secretKey, iv).doFinal(payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a cipher in {@link Cipher#ENCRYPT_MODE}.
|
||||
*
|
||||
* @param secretKey The secret key.
|
||||
* @param iv The initialization vector.
|
||||
* @return The initialized cipher.
|
||||
*/
|
||||
public static Cipher startEncrypt(SecretKey secretKey, byte[] iv) throws NoSuchPaddingException,
|
||||
NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
|
||||
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
||||
return cipher.doFinal(payload);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,8 +59,21 @@ public class CipherUtil {
|
|||
NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException,
|
||||
InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
|
||||
return startDecrypt(secretKey, iv).doFinal(payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a cipher in {@link Cipher#DECRYPT_MODE}.
|
||||
*
|
||||
* @param secretKey The secret key.
|
||||
* @param iv The initialization vector.
|
||||
* @return The initialized cipher.
|
||||
*/
|
||||
public static Cipher startDecrypt(SecretKey secretKey, byte[] iv) throws NoSuchPaddingException,
|
||||
NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
|
||||
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
||||
return cipher.doFinal(payload);
|
||||
return cipher;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public class KeyGenerator {
|
|||
/**
|
||||
* The number of iterations for key generation.
|
||||
*/
|
||||
private static final int ITERATIONS = 25;
|
||||
private static final int ITERATIONS = 32767;
|
||||
|
||||
/**
|
||||
* The generated key length.
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.stevesoltys.backup.transport.component.BackupComponent;
|
|||
import libcore.io.IoUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -44,6 +45,30 @@ public class ContentProviderBackupComponent implements BackupComponent {
|
|||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelFullBackup() {
|
||||
clearBackupState(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkFullBackupSize(long size) {
|
||||
int result = TRANSPORT_OK;
|
||||
|
||||
if (size <= 0) {
|
||||
result = TRANSPORT_PACKAGE_REJECTED;
|
||||
|
||||
} else if (size > configuration.getBackupSizeQuota()) {
|
||||
result = TRANSPORT_QUOTA_EXCEEDED;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clearBackupData(PackageInfo packageInfo) {
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentDestinationString() {
|
||||
return DESTINATION_DESCRIPTION;
|
||||
|
@ -54,85 +79,19 @@ public class ContentProviderBackupComponent implements BackupComponent {
|
|||
return TRANSPORT_DATA_MANAGEMENT_LABEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int initializeDevice() {
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clearBackupData(PackageInfo packageInfo) {
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int finishBackup() {
|
||||
return clearBackupState(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int performIncrementalBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
|
||||
BackupDataInput backupDataInput = new BackupDataInput(data.getFileDescriptor());
|
||||
|
||||
try {
|
||||
initializeBackupState();
|
||||
backupState.setPackageIndex(backupState.getPackageIndex() + 1);
|
||||
backupState.setPackageName(packageInfo.packageName);
|
||||
|
||||
return transferIncrementalBackupData(backupDataInput);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error reading backup input: ", ex);
|
||||
return TRANSPORT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private int clearBackupState(boolean closeFile) {
|
||||
|
||||
if (backupState == null) {
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
try {
|
||||
IoUtils.closeQuietly(backupState.getInputFileDescriptor());
|
||||
backupState.setInputFileDescriptor(null);
|
||||
|
||||
ZipOutputStream outputStream = backupState.getOutputStream();
|
||||
|
||||
if (outputStream != null) {
|
||||
outputStream.closeEntry();
|
||||
}
|
||||
|
||||
if (backupState.getPackageIndex() == configuration.getPackageCount() || closeFile) {
|
||||
if (outputStream != null) {
|
||||
outputStream.finish();
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
IoUtils.closeQuietly(backupState.getOutputFileDescriptor());
|
||||
backupState = null;
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "Error cancelling full backup: ", ex);
|
||||
return TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBackupQuota(String packageName, boolean fullBackup) {
|
||||
return configuration.getBackupSizeQuota();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long requestBackupTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long requestFullBackupTime() {
|
||||
return 0;
|
||||
public int initializeDevice() {
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,6 +111,9 @@ public class ContentProviderBackupComponent implements BackupComponent {
|
|||
backupState.setInputStream(new FileInputStream(fileDescriptor.getFileDescriptor()));
|
||||
backupState.setBytesTransferred(0);
|
||||
|
||||
Cipher cipher = CipherUtil.startEncrypt(backupState.getSecretKey(), backupState.getSalt());
|
||||
backupState.setCipher(cipher);
|
||||
|
||||
ZipEntry zipEntry = new ZipEntry(configuration.getFullBackupDirectory() + backupState.getPackageName());
|
||||
backupState.getOutputStream().putNextEntry(zipEntry);
|
||||
|
||||
|
@ -165,17 +127,30 @@ public class ContentProviderBackupComponent implements BackupComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int checkFullBackupSize(long size) {
|
||||
int result = TRANSPORT_OK;
|
||||
public int performIncrementalBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
|
||||
BackupDataInput backupDataInput = new BackupDataInput(data.getFileDescriptor());
|
||||
|
||||
if (size <= 0) {
|
||||
result = TRANSPORT_PACKAGE_REJECTED;
|
||||
try {
|
||||
initializeBackupState();
|
||||
backupState.setPackageIndex(backupState.getPackageIndex() + 1);
|
||||
backupState.setPackageName(packageInfo.packageName);
|
||||
|
||||
} else if (size > configuration.getBackupSizeQuota()) {
|
||||
result = TRANSPORT_QUOTA_EXCEEDED;
|
||||
return transferIncrementalBackupData(backupDataInput);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error reading backup input: ", ex);
|
||||
return TRANSPORT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@Override
|
||||
public long requestBackupTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long requestFullBackupTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -196,51 +171,22 @@ public class ContentProviderBackupComponent implements BackupComponent {
|
|||
ZipOutputStream outputStream = backupState.getOutputStream();
|
||||
|
||||
try {
|
||||
outputStream.write(IOUtils.readFully(inputStream, numBytes));
|
||||
byte[] payload = IOUtils.readFully(inputStream, numBytes);
|
||||
|
||||
if (backupState.getCipher() != null) {
|
||||
payload = backupState.getCipher().update(payload);
|
||||
}
|
||||
|
||||
outputStream.write(payload, 0, numBytes);
|
||||
backupState.setBytesTransferred(bytesTransferred);
|
||||
|
||||
} catch (IOException ex) {
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error handling backup data for " + backupState.getPackageName() + ": ", ex);
|
||||
return TRANSPORT_ERROR;
|
||||
}
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelFullBackup() {
|
||||
clearBackupState(false);
|
||||
}
|
||||
|
||||
private void initializeBackupState() throws Exception {
|
||||
if (backupState == null) {
|
||||
backupState = new ContentProviderBackupState();
|
||||
}
|
||||
|
||||
if (backupState.getOutputStream() == null) {
|
||||
initializeOutputStream();
|
||||
|
||||
ZipEntry saltZipEntry = new ZipEntry(ContentProviderBackupConstants.SALT_FILE_PATH);
|
||||
backupState.getOutputStream().putNextEntry(saltZipEntry);
|
||||
backupState.getOutputStream().write(backupState.getSalt());
|
||||
backupState.getOutputStream().closeEntry();
|
||||
|
||||
|
||||
if (configuration.getPassword() != null && !configuration.getPassword().isEmpty()) {
|
||||
backupState.setSecretKey(KeyGenerator.generate(configuration.getPassword(), backupState.getSalt()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeOutputStream() throws IOException {
|
||||
ContentResolver contentResolver = configuration.getContext().getContentResolver();
|
||||
ParcelFileDescriptor outputFileDescriptor = contentResolver.openFileDescriptor(configuration.getUri(), "w");
|
||||
backupState.setOutputFileDescriptor(outputFileDescriptor);
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(outputFileDescriptor.getFileDescriptor());
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
|
||||
backupState.setOutputStream(zipOutputStream);
|
||||
}
|
||||
|
||||
private int transferIncrementalBackupData(BackupDataInput backupDataInput) throws IOException {
|
||||
ZipOutputStream outputStream = backupState.getOutputStream();
|
||||
|
||||
|
@ -285,4 +231,73 @@ public class ContentProviderBackupComponent implements BackupComponent {
|
|||
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
private void initializeBackupState() throws Exception {
|
||||
if (backupState == null) {
|
||||
backupState = new ContentProviderBackupState();
|
||||
}
|
||||
|
||||
if (backupState.getOutputStream() == null) {
|
||||
initializeOutputStream();
|
||||
|
||||
ZipEntry saltZipEntry = new ZipEntry(ContentProviderBackupConstants.SALT_FILE_PATH);
|
||||
backupState.getOutputStream().putNextEntry(saltZipEntry);
|
||||
backupState.getOutputStream().write(backupState.getSalt());
|
||||
backupState.getOutputStream().closeEntry();
|
||||
|
||||
if (configuration.getPassword() != null && !configuration.getPassword().isEmpty()) {
|
||||
backupState.setSecretKey(KeyGenerator.generate(configuration.getPassword(), backupState.getSalt()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeOutputStream() throws IOException {
|
||||
ContentResolver contentResolver = configuration.getContext().getContentResolver();
|
||||
ParcelFileDescriptor outputFileDescriptor = contentResolver.openFileDescriptor(configuration.getUri(), "w");
|
||||
backupState.setOutputFileDescriptor(outputFileDescriptor);
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(outputFileDescriptor.getFileDescriptor());
|
||||
ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
|
||||
backupState.setOutputStream(zipOutputStream);
|
||||
}
|
||||
|
||||
private int clearBackupState(boolean closeFile) {
|
||||
|
||||
if (backupState == null) {
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
try {
|
||||
IoUtils.closeQuietly(backupState.getInputFileDescriptor());
|
||||
backupState.setInputFileDescriptor(null);
|
||||
|
||||
ZipOutputStream outputStream = backupState.getOutputStream();
|
||||
|
||||
if (outputStream != null) {
|
||||
|
||||
if (backupState.getCipher() != null) {
|
||||
outputStream.write(backupState.getCipher().doFinal());
|
||||
backupState.setCipher(null);
|
||||
}
|
||||
|
||||
outputStream.closeEntry();
|
||||
}
|
||||
|
||||
if (backupState.getPackageIndex() == configuration.getPackageCount() || closeFile) {
|
||||
if (outputStream != null) {
|
||||
outputStream.finish();
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
IoUtils.closeQuietly(backupState.getOutputFileDescriptor());
|
||||
backupState = null;
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error cancelling full backup: ", ex);
|
||||
return TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
return TRANSPORT_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.stevesoltys.backup.transport.component.provider;
|
|||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.io.InputStream;
|
||||
import java.security.SecureRandom;
|
||||
|
@ -22,6 +23,8 @@ class ContentProviderBackupState {
|
|||
|
||||
private ZipOutputStream outputStream;
|
||||
|
||||
private Cipher cipher;
|
||||
|
||||
private long bytesTransferred;
|
||||
|
||||
private String packageName;
|
||||
|
@ -45,6 +48,14 @@ class ContentProviderBackupState {
|
|||
this.bytesTransferred = bytesTransferred;
|
||||
}
|
||||
|
||||
Cipher getCipher() {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
void setCipher(Cipher cipher) {
|
||||
this.cipher = cipher;
|
||||
}
|
||||
|
||||
ParcelFileDescriptor getInputFileDescriptor() {
|
||||
return inputFileDescriptor;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import libcore.io.Streams;
|
|||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -166,29 +167,6 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
|
|||
return TRANSPORT_OK;
|
||||
}
|
||||
|
||||
private ParcelFileDescriptor buildInputFileDescriptor() throws FileNotFoundException {
|
||||
ContentResolver contentResolver = configuration.getContext().getContentResolver();
|
||||
return contentResolver.openFileDescriptor(configuration.getUri(), "r");
|
||||
}
|
||||
|
||||
private ZipInputStream buildInputStream(ParcelFileDescriptor inputFileDescriptor) throws FileNotFoundException {
|
||||
FileInputStream fileInputStream = new FileInputStream(inputFileDescriptor.getFileDescriptor());
|
||||
return new ZipInputStream(fileInputStream);
|
||||
}
|
||||
|
||||
private Optional<ZipEntry> seekToEntry(ZipInputStream inputStream, String entryPath) throws IOException {
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = inputStream.getNextEntry()) != null) {
|
||||
|
||||
if (zipEntry.getName().startsWith(entryPath)) {
|
||||
return Optional.of(zipEntry);
|
||||
}
|
||||
inputStream.closeEntry();
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private byte[] readBackupData(ZipInputStream inputStream) throws Exception {
|
||||
byte[] backupData = Streams.readFullyNoClose(inputStream);
|
||||
SecretKey secretKey = restoreState.getSecretKey();
|
||||
|
@ -248,7 +226,28 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
|
|||
|
||||
if (bytesRead <= 0) {
|
||||
bytesRead = NO_MORE_DATA;
|
||||
|
||||
if (restoreState.getCipher() != null) {
|
||||
buffer = restoreState.getCipher().doFinal();
|
||||
bytesRead = buffer.length;
|
||||
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
restoreState.setCipher(null);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (restoreState.getSecretKey() != null) {
|
||||
SecretKey secretKey = restoreState.getSecretKey();
|
||||
byte[] salt = restoreState.getSalt();
|
||||
|
||||
if (restoreState.getCipher() == null) {
|
||||
restoreState.setCipher(CipherUtil.startDecrypt(secretKey, salt));
|
||||
}
|
||||
|
||||
buffer = restoreState.getCipher().update(Arrays.copyOfRange(buffer, 0, bytesRead));
|
||||
bytesRead = buffer.length;
|
||||
}
|
||||
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
|
@ -305,4 +304,27 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
|
|||
IoUtils.closeQuietly(restoreState.getInputFileDescriptor());
|
||||
restoreState = null;
|
||||
}
|
||||
|
||||
private ParcelFileDescriptor buildInputFileDescriptor() throws FileNotFoundException {
|
||||
ContentResolver contentResolver = configuration.getContext().getContentResolver();
|
||||
return contentResolver.openFileDescriptor(configuration.getUri(), "r");
|
||||
}
|
||||
|
||||
private ZipInputStream buildInputStream(ParcelFileDescriptor inputFileDescriptor) throws FileNotFoundException {
|
||||
FileInputStream fileInputStream = new FileInputStream(inputFileDescriptor.getFileDescriptor());
|
||||
return new ZipInputStream(fileInputStream);
|
||||
}
|
||||
|
||||
private Optional<ZipEntry> seekToEntry(ZipInputStream inputStream, String entryPath) throws IOException {
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = inputStream.getNextEntry()) != null) {
|
||||
|
||||
if (zipEntry.getName().startsWith(entryPath)) {
|
||||
return Optional.of(zipEntry);
|
||||
}
|
||||
inputStream.closeEntry();
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.stevesoltys.backup.transport.component.provider;
|
|||
import android.content.pm.PackageInfo;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
@ -23,16 +24,26 @@ class ContentProviderRestoreState {
|
|||
|
||||
private ZipInputStream inputStream;
|
||||
|
||||
private Cipher cipher;
|
||||
|
||||
private byte[] salt;
|
||||
|
||||
private SecretKey secretKey;
|
||||
|
||||
private List<ZipEntry> zipEntries;
|
||||
|
||||
Cipher getCipher() {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
ParcelFileDescriptor getInputFileDescriptor() {
|
||||
return inputFileDescriptor;
|
||||
}
|
||||
|
||||
void setCipher(Cipher cipher) {
|
||||
this.cipher = cipher;
|
||||
}
|
||||
|
||||
void setInputFileDescriptor(ParcelFileDescriptor inputFileDescriptor) {
|
||||
this.inputFileDescriptor = inputFileDescriptor;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,21 @@ import com.stevesoltys.backup.transport.component.BackupComponent;
|
|||
*/
|
||||
public class StubBackupComponent implements BackupComponent {
|
||||
|
||||
@Override
|
||||
public void cancelFullBackup() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkFullBackupSize(long size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clearBackupData(PackageInfo packageInfo) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentDestinationString() {
|
||||
return null;
|
||||
|
@ -19,23 +34,18 @@ public class StubBackupComponent implements BackupComponent {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int initializeDevice() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clearBackupData(PackageInfo packageInfo) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int finishBackup() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int performIncrementalBackup(PackageInfo targetPackage, ParcelFileDescriptor data) {
|
||||
public long getBackupQuota(String packageName, boolean fullBackup) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int initializeDevice() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -45,22 +55,7 @@ public class StubBackupComponent implements BackupComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int checkFullBackupSize(long size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendBackupData(int numBytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelFullBackup() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBackupQuota(String packageName, boolean fullBackup) {
|
||||
public int performIncrementalBackup(PackageInfo targetPackage, ParcelFileDescriptor data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -73,4 +68,9 @@ public class StubBackupComponent implements BackupComponent {
|
|||
public long requestFullBackupTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendBackupData(int numBytes) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue