Merge changes I17264f0e,I0581978f am: 06c8be69b9

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1902510

Change-Id: I30faa68caf5a55504b1b8cc3c9b958c308a9b120
This commit is contained in:
Kevin Rocard
2022-02-04 11:41:27 +00:00
committed by Automerger Merge Worker
4 changed files with 67 additions and 11 deletions

View File

@@ -103,6 +103,7 @@ public class MtpDatabase implements AutoCloseable {
private int mDeviceType; private int mDeviceType;
private String mHostType; private String mHostType;
private boolean mSkipThumbForHost = false; private boolean mSkipThumbForHost = false;
private volatile boolean mHostIsWindows = false;
private MtpServer mServer; private MtpServer mServer;
private MtpStorageManager mManager; private MtpStorageManager mManager;
@@ -358,7 +359,7 @@ public class MtpDatabase implements AutoCloseable {
} }
public void addStorage(StorageVolume storage) { public void addStorage(StorageVolume storage) {
MtpStorage mtpStorage = mManager.addMtpStorage(storage); MtpStorage mtpStorage = mManager.addMtpStorage(storage, () -> mHostIsWindows);
mStorageMap.put(storage.getPath(), mtpStorage); mStorageMap.put(storage.getPath(), mtpStorage);
if (mServer != null) { if (mServer != null) {
mServer.addStorage(mtpStorage); mServer.addStorage(mtpStorage);
@@ -413,6 +414,7 @@ public class MtpDatabase implements AutoCloseable {
} }
mHostType = ""; mHostType = "";
mSkipThumbForHost = false; mSkipThumbForHost = false;
mHostIsWindows = false;
} }
@VisibleForNative @VisibleForNative
@@ -736,10 +738,12 @@ public class MtpDatabase implements AutoCloseable {
: MtpConstants.RESPONSE_GENERAL_ERROR); : MtpConstants.RESPONSE_GENERAL_ERROR);
case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO: case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
mHostType = stringValue; mHostType = stringValue;
Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
+ "=" + stringValue);
if (stringValue.startsWith("Android/")) { if (stringValue.startsWith("Android/")) {
Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
+ "=" + stringValue);
mSkipThumbForHost = true; mSkipThumbForHost = true;
} else if (stringValue.startsWith("Windows/")) {
mHostIsWindows = true;
} }
return MtpConstants.RESPONSE_OK; return MtpConstants.RESPONSE_OK;
} }

View File

@@ -19,6 +19,8 @@ package android.mtp;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.os.storage.StorageVolume; import android.os.storage.StorageVolume;
import java.util.function.Supplier;
/** /**
* This class represents a storage unit on an MTP device. * This class represents a storage unit on an MTP device.
* Used only for MTP support in USB responder mode. * Used only for MTP support in USB responder mode.
@@ -33,14 +35,16 @@ public class MtpStorage {
private final boolean mRemovable; private final boolean mRemovable;
private final long mMaxFileSize; private final long mMaxFileSize;
private final String mVolumeName; private final String mVolumeName;
private final Supplier<Boolean> mIsHostWindows;
public MtpStorage(StorageVolume volume, int storageId) { public MtpStorage(StorageVolume volume, int storageId, Supplier<Boolean> isHostWindows) {
mStorageId = storageId; mStorageId = storageId;
mPath = volume.getPath(); mPath = volume.getPath();
mDescription = volume.getDescription(null); mDescription = volume.getDescription(null);
mRemovable = volume.isRemovable(); mRemovable = volume.isRemovable();
mMaxFileSize = volume.getMaxFileSize(); mMaxFileSize = volume.getMaxFileSize();
mVolumeName = volume.getMediaStoreVolumeName(); mVolumeName = volume.getMediaStoreVolumeName();
mIsHostWindows = isHostWindows;
} }
/** /**
@@ -93,4 +97,13 @@ public class MtpStorage {
public String getVolumeName() { public String getVolumeName() {
return mVolumeName; return mVolumeName;
} }
/**
* Returns true if the mtp host of this storage is Windows.
*
* @return is host Windows
*/
public boolean isHostWindows() {
return mIsHostWindows.get();
}
} }

View File

@@ -18,7 +18,11 @@ package android.mtp;
import android.media.MediaFile; import android.media.MediaFile;
import android.os.FileObserver; import android.os.FileObserver;
import android.os.SystemProperties;
import android.os.storage.StorageVolume; import android.os.storage.StorageVolume;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
import android.util.Log; import android.util.Log;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
@@ -35,6 +39,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
/** /**
* MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of * MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of
@@ -199,7 +204,38 @@ public class MtpStorageManager {
} }
public long getSize() { 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 (mStorage.isHostWindows() && 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() { public Path getPath() {
@@ -420,10 +456,12 @@ public class MtpStorageManager {
* @param volume Storage to add. * @param volume Storage to add.
* @return the associated MtpStorage * @return the associated MtpStorage
*/ */
public synchronized MtpStorage addMtpStorage(StorageVolume volume) { public synchronized MtpStorage addMtpStorage(StorageVolume volume,
Supplier<Boolean> isHostWindows) {
int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1; int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1;
MtpStorage storage = new MtpStorage(volume, storageId); MtpStorage storage = new MtpStorage(volume, storageId, isHostWindows);
MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true); MtpObject root = new MtpObject(storage.getPath(), storageId, storage, /* parent= */ null,
/* isDir= */ true);
mRoots.put(storageId, root); mRoots.put(storageId, root);
return storage; return storage;
} }

View File

@@ -159,10 +159,11 @@ public class MtpStorageManagerTest {
Log.d(TAG, "sendObjectInfoChanged: " + id); Log.d(TAG, "sendObjectInfoChanged: " + id);
objectsInfoChanged.add(id); objectsInfoChanged.add(id);
} }
}, null); }, /* subdirectories= */ null);
mainMtpStorage = manager.addMtpStorage(mainStorage); mainMtpStorage = manager.addMtpStorage(mainStorage, /* isHostWindows= */ () -> false);
secondaryMtpStorage = manager.addMtpStorage(secondaryStorage); secondaryMtpStorage = manager.addMtpStorage(secondaryStorage,
/* isHostWindows= */ () -> false);
} }
@After @After