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

Commit 9310e428 authored by Christopher Tate's avatar Christopher Tate Committed by Chris Tate
Browse files

Avoid zero-payload backups in local transport

The local debugging transport now implements
BackupTransport.checkFullBackupSize() to detect and reject backup attempts
for which no actual file content will be committed.  The documentation for
checkFullBackupSize() has also been expanded to document the transport's
responsibilities in this regard.

The local transport now lazy-creates the destination file when data is
first delivered for an approved backup operation, rather than doing it
proactively in performBackup(), to ensure that changes in the datastore
are only attempted after the transport has positive confirmation that
data is indeed flowing.

Change-Id: I6e47a7e72cd938fc0ed31da4bc490540c71f9e65
parent 2f77da07
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -399,6 +399,13 @@ public class BackupTransport {
     * operation will be skipped (and {@link #finishBackup() invoked} with no data for that
     * package being passed to {@link #sendBackupData}.
     *
     * <p class="note">The platform does no size-based rejection of full backup attempts on
     * its own: it is always the responsibility of the transport to implement its own policy.
     * In particular, even if the preflighted payload size is zero, the platform will still call
     * this method and will proceed to back up an archive metadata header with no file content
     * if this method returns TRANSPORT_OK.  To avoid storing such payloads the transport
     * must recognize this case and return TRANSPORT_PACKAGE_REJECTED.
     *
     * Added in MNC (API 23).
     *
     * @param size The estimated size of the full-data payload for this app.  This includes
+36 −17
Original line number Diff line number Diff line
@@ -45,8 +45,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import static android.system.OsConstants.*;
import static android.system.OsConstants.SEEK_CUR;

/**
 * Backup transport for stashing stuff into a known location on disk, and
@@ -284,8 +283,10 @@ public class LocalTransport extends BackupTransport {
    private int tearDownFullBackup() {
        if (mSocket != null) {
            try {
                if (mFullBackupOutputStream != null) {
                    mFullBackupOutputStream.flush();
                    mFullBackupOutputStream.close();
                }
                mSocketInputStream = null;
                mFullTargetPackage = null;
                mSocket.close();
@@ -296,6 +297,7 @@ public class LocalTransport extends BackupTransport {
                return TRANSPORT_ERROR;
            } finally {
                mSocket = null;
                mFullBackupOutputStream = null;
            }
        }
        return TRANSPORT_OK;
@@ -310,6 +312,18 @@ public class LocalTransport extends BackupTransport {
        return 0;
    }

    @Override
    public int checkFullBackupSize(long size) {
        // Decline zero-size "backups"
        final int result = (size > 0) ? TRANSPORT_OK : TRANSPORT_PACKAGE_REJECTED;
        if (result != TRANSPORT_OK) {
            if (DEBUG) {
                Log.v(TAG, "Declining backup of size " + size);
            }
        }
        return result;
    }

    @Override
    public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
        if (mSocket != null) {
@@ -333,22 +347,14 @@ public class LocalTransport extends BackupTransport {
        }

        mFullTargetPackage = targetPackage.packageName;
        FileOutputStream tarstream;
        try {
            File tarball = tarballFile(mFullTargetPackage);
            tarstream = new FileOutputStream(tarball);
        } catch (FileNotFoundException e) {
            return TRANSPORT_ERROR;
        }
        mFullBackupOutputStream = new BufferedOutputStream(tarstream);
        mFullBackupBuffer = new byte[4096];

        return TRANSPORT_OK;
    }

    @Override
    public int sendBackupData(int numBytes) {
        if (mFullBackupBuffer == null) {
    public int sendBackupData(final int numBytes) {
        if (mSocket == null) {
            Log.w(TAG, "Attempted sendBackupData before performFullBackup");
            return TRANSPORT_ERROR;
        }
@@ -356,16 +362,29 @@ public class LocalTransport extends BackupTransport {
        if (numBytes > mFullBackupBuffer.length) {
            mFullBackupBuffer = new byte[numBytes];
        }
        while (numBytes > 0) {

        if (mFullBackupOutputStream == null) {
            FileOutputStream tarstream;
            try {
                File tarball = tarballFile(mFullTargetPackage);
                tarstream = new FileOutputStream(tarball);
            } catch (FileNotFoundException e) {
                return TRANSPORT_ERROR;
            }
            mFullBackupOutputStream = new BufferedOutputStream(tarstream);
        }

        int bytesLeft = numBytes;
        while (bytesLeft > 0) {
            try {
            int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, numBytes);
            int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft);
            if (nRead < 0) {
                // Something went wrong if we expect data but saw EOD
                Log.w(TAG, "Unexpected EOD; failing backup");
                return TRANSPORT_ERROR;
            }
            mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
            numBytes -= nRead;
            bytesLeft -= nRead;
            } catch (IOException e) {
                Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
                return TRANSPORT_ERROR;