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

Commit 1cfc0c74 authored by Zim's avatar Zim Committed by Kevin Rocard
Browse files

Workaround to fixup MTP transcode file size

Some Windows MTP clients ignore the file size sent from the server
while sending MTP objects, and instead rely on the cached MTP metadata
containing the size. This causes file corruption when transcoded files
are transferred from phone to PC because the file is truncated to the
original file size from the cached metadata which is smaller than the
transcoded file size.

To workaround this, MediaProvider added an ugly workaround to the
struct stat st_nlink field to signal when a file requires
transcoding. In such cases, the MTP server can double the metadata
size, the same heuristic used in the MediaProvider to accommodate the
transcoded file size.

Test: atest MtpTests
Bug: 184117074
Bug: 190422448
Change-Id: I0581978fb346e3dc2d7a5204ffd7c601b61ec749
parent 42bf9da7
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
@@ -18,7 +18,11 @@ package android.mtp;

import android.media.MediaFile;
import android.os.FileObserver;
import android.os.SystemProperties;
import android.os.storage.StorageVolume;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
import android.util.Log;

import com.android.internal.util.Preconditions;
@@ -199,7 +203,38 @@ public class MtpStorageManager {
        }

        public long getSize() {
            return mIsDir ? 0 : getPath().toFile().length();
            return mIsDir ? 0 : maybeApplyTranscodeLengthWorkaround(getPath().toFile().length());
        }

        private long maybeApplyTranscodeLengthWorkaround(long length) {
            // Windows truncates transferred files to the size advertised in the object property.
            if (isTranscodeMtpEnabled() && isFileTranscodeSupported()) {
                // If the file supports transcoding, we double the returned size to accommodate
                // the increase in size from transcoding to AVC. This is the same heuristic
                // applied in the FUSE daemon (MediaProvider).
                return length * 2;
            }
            return length;
        }

        private boolean isTranscodeMtpEnabled() {
            return SystemProperties.getBoolean("sys.fuse.transcode_mtp", false);
        }

        private boolean isFileTranscodeSupported() {
            // Check if the file supports transcoding by reading the |st_nlinks| struct stat
            // field. This will be > 1 if the file supports transcoding. The FUSE daemon
            // sets the field accordingly to enable the MTP stack workaround some Windows OS
            // MTP client bug where they ignore the size returned as part of getting the MTP
            // object, see MtpServer#doGetObject.
            final Path path = getPath();
            try {
                StructStat stat = Os.stat(path.toString());
                return stat.st_nlink > 1;
            } catch (ErrnoException e) {
                Log.w(TAG, "Failed to stat path: " + getPath() + ". Ignoring transcoding.");
                return false;
            }
        }

        public Path getPath() {