Merge "Refactor FileUtils#convertToModernFd" into sc-dev
This commit is contained in:
@@ -46,8 +46,6 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ProviderInfo;
|
import android.content.pm.ProviderInfo;
|
||||||
import android.content.res.AssetFileDescriptor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.DocumentsContract.Document;
|
import android.provider.DocumentsContract.Document;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
@@ -83,7 +81,6 @@ import java.security.NoSuchAlgorithmException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -1446,46 +1443,22 @@ public final class FileUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/170488060): Consider better approach
|
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static FileDescriptor convertToModernFd(FileDescriptor fd) {
|
public static ParcelFileDescriptor convertToModernFd(FileDescriptor fd) {
|
||||||
try {
|
try {
|
||||||
Context context = AppGlobals.getInitialApplication();
|
Context context = AppGlobals.getInitialApplication();
|
||||||
// /mnt/user paths are not accessible directly so convert to a /storage path
|
if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
|
||||||
String filePath = Os.readlink("/proc/self/fd/" + fd.getInt$()).replace(
|
// Never convert modern fd for MediaProvider, because this requires
|
||||||
"/mnt/user/" + UserHandle.myUserId(), "/storage");
|
|
||||||
File realFile = new File(filePath);
|
|
||||||
String fileName = realFile.getName();
|
|
||||||
boolean isCameraVideo = !fileName.startsWith(".") && fileName.endsWith(".mp4")
|
|
||||||
&& contains(CAMERA_DIR_LOWER_CASE, filePath.toLowerCase(Locale.ROOT));
|
|
||||||
|
|
||||||
if (!SystemProperties.getBoolean("sys.fuse.transcode_enabled", false)
|
|
||||||
|| UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)
|
|
||||||
|| !isCameraVideo) {
|
|
||||||
// 1. If transcode is enabled we optimize by default, unless explicitly disabled.
|
|
||||||
// 2. Never convert modern fd for MediaProvider, because this requires
|
|
||||||
// MediaStore#scanFile and can cause infinite loops when MediaProvider scans
|
// MediaStore#scanFile and can cause infinite loops when MediaProvider scans
|
||||||
// 3. Only convert published mp4 videos in the DCIM/Camera dir
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Log.i(TAG, "Changing to modern format dataSource for: " + realFile);
|
return MediaStore.getOriginalMediaFormatFileDescriptor(context,
|
||||||
ContentResolver resolver = context.getContentResolver();
|
ParcelFileDescriptor.dup(fd));
|
||||||
|
|
||||||
Uri uri = MediaStore.scanFile(resolver, realFile);
|
|
||||||
if (uri != null) {
|
|
||||||
Bundle opts = new Bundle();
|
|
||||||
opts.putBoolean(MediaStore.EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT, true);
|
|
||||||
AssetFileDescriptor afd = resolver.openTypedAssetFileDescriptor(uri, "*/*", opts);
|
|
||||||
Log.i(TAG, "Changed to modern format dataSource for: " + realFile);
|
|
||||||
return afd.getFileDescriptor();
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "Failed to change to modern format dataSource for: " + realFile);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, "Failed to change to modern format dataSource", e);
|
Log.w(TAG, "Failed to convert to modern format file descriptor", e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getMediaProviderAppId(Context context) {
|
private static int getMediaProviderAppId(Context context) {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import android.content.res.AssetManager;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.os.FileUtils;
|
import android.os.FileUtils;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
@@ -1531,16 +1532,24 @@ public class ExifInterface {
|
|||||||
if (fileDescriptor == null) {
|
if (fileDescriptor == null) {
|
||||||
throw new NullPointerException("fileDescriptor cannot be null");
|
throw new NullPointerException("fileDescriptor cannot be null");
|
||||||
}
|
}
|
||||||
FileDescriptor modernFd = FileUtils.convertToModernFd(fileDescriptor);
|
// If a file descriptor has a modern file descriptor, this means that the file can be
|
||||||
|
// transcoded and not using the modern file descriptor will trigger the transcoding
|
||||||
|
// operation. Thus, to avoid unnecessary transcoding, need to convert to modern file
|
||||||
|
// descriptor if it exists. As of Android S, transcoding is not supported for image files,
|
||||||
|
// so this is for protecting against non-image files sent to ExifInterface, but support may
|
||||||
|
// be added in the future.
|
||||||
|
ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fileDescriptor);
|
||||||
if (modernFd != null) {
|
if (modernFd != null) {
|
||||||
fileDescriptor = modernFd;
|
fileDescriptor = modernFd.getFileDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
mAssetInputStream = null;
|
mAssetInputStream = null;
|
||||||
mFilename = null;
|
mFilename = null;
|
||||||
|
|
||||||
boolean isFdDuped = false;
|
boolean isFdDuped = false;
|
||||||
if (isSeekableFD(fileDescriptor)) {
|
// Can't save attributes to files with transcoding because apps get a different copy of
|
||||||
|
// that file when they're not using it through framework libraries like ExifInterface.
|
||||||
|
if (isSeekableFD(fileDescriptor) && modernFd == null) {
|
||||||
mSeekableFileDescriptor = fileDescriptor;
|
mSeekableFileDescriptor = fileDescriptor;
|
||||||
// Keep the original file descriptor in order to save attributes when it's seekable.
|
// Keep the original file descriptor in order to save attributes when it's seekable.
|
||||||
// Otherwise, just close the given file descriptor after reading it because the save
|
// Otherwise, just close the given file descriptor after reading it because the save
|
||||||
@@ -2545,27 +2554,22 @@ public class ExifInterface {
|
|||||||
|
|
||||||
private void initForFilename(String filename) throws IOException {
|
private void initForFilename(String filename) throws IOException {
|
||||||
FileInputStream in = null;
|
FileInputStream in = null;
|
||||||
FileInputStream legacyInputStream = null;
|
|
||||||
mAssetInputStream = null;
|
mAssetInputStream = null;
|
||||||
mFilename = filename;
|
mFilename = filename;
|
||||||
mIsInputStream = false;
|
mIsInputStream = false;
|
||||||
try {
|
try {
|
||||||
in = new FileInputStream(filename);
|
in = new FileInputStream(filename);
|
||||||
FileDescriptor modernFd = FileUtils.convertToModernFd(in.getFD());
|
ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(in.getFD());
|
||||||
if (modernFd != null) {
|
if (modernFd != null) {
|
||||||
legacyInputStream = in;
|
closeQuietly(in);
|
||||||
in = new FileInputStream(modernFd);
|
in = new FileInputStream(modernFd.getFileDescriptor());
|
||||||
}
|
|
||||||
|
|
||||||
if (isSeekableFD(in.getFD())) {
|
|
||||||
mSeekableFileDescriptor = in.getFD();
|
|
||||||
} else {
|
|
||||||
mSeekableFileDescriptor = null;
|
mSeekableFileDescriptor = null;
|
||||||
|
} else if (isSeekableFD(in.getFD())) {
|
||||||
|
mSeekableFileDescriptor = in.getFD();
|
||||||
}
|
}
|
||||||
loadAttributes(in);
|
loadAttributes(in);
|
||||||
} finally {
|
} finally {
|
||||||
closeQuietly(in);
|
closeQuietly(in);
|
||||||
closeQuietly(legacyInputStream);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.FileUtils;
|
import android.os.FileUtils;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
@@ -300,11 +301,11 @@ public class MediaMetadataRetriever implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
public void setDataSource(FileDescriptor fd, long offset, long length)
|
public void setDataSource(FileDescriptor fd, long offset, long length)
|
||||||
throws IllegalArgumentException {
|
throws IllegalArgumentException {
|
||||||
FileDescriptor modernFd = FileUtils.convertToModernFd(fd);
|
ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
|
||||||
if (modernFd == null) {
|
if (modernFd == null) {
|
||||||
_setDataSource(fd, offset, length);
|
_setDataSource(fd, offset, length);
|
||||||
} else {
|
} else {
|
||||||
_setDataSource(modernFd, offset, length);
|
_setDataSource(modernFd.getFileDescriptor(), offset, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import android.os.IBinder;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
@@ -97,7 +98,6 @@ import java.util.UUID;
|
|||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MediaPlayer class can be used to control playback of audio/video files and streams.
|
* MediaPlayer class can be used to control playback of audio/video files and streams.
|
||||||
*
|
*
|
||||||
@@ -1268,11 +1268,11 @@ public class MediaPlayer extends PlayerBase
|
|||||||
*/
|
*/
|
||||||
public void setDataSource(FileDescriptor fd, long offset, long length)
|
public void setDataSource(FileDescriptor fd, long offset, long length)
|
||||||
throws IOException, IllegalArgumentException, IllegalStateException {
|
throws IOException, IllegalArgumentException, IllegalStateException {
|
||||||
FileDescriptor modernFd = FileUtils.convertToModernFd(fd);
|
ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
|
||||||
if (modernFd == null) {
|
if (modernFd == null) {
|
||||||
_setDataSource(fd, offset, length);
|
_setDataSource(fd, offset, length);
|
||||||
} else {
|
} else {
|
||||||
_setDataSource(modernFd, offset, length);
|
_setDataSource(modernFd.getFileDescriptor(), offset, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user