Loading core/java/android/os/FileUtils.java +7 −34 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -1446,47 +1443,23 @@ 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) { if (sMediaProviderAppId != -1) { if (sMediaProviderAppId != -1) { Loading media/java/android/media/ExifInterface.java +17 −13 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); } } } } Loading media/java/android/media/MediaMetadataRetriever.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } } Loading media/java/android/media/MediaPlayer.java +3 −3 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. * * Loading Loading @@ -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); } } } } Loading Loading
core/java/android/os/FileUtils.java +7 −34 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -1446,47 +1443,23 @@ 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) { if (sMediaProviderAppId != -1) { if (sMediaProviderAppId != -1) { Loading
media/java/android/media/ExifInterface.java +17 −13 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); } } } } Loading
media/java/android/media/MediaMetadataRetriever.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } } Loading
media/java/android/media/MediaPlayer.java +3 −3 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. * * Loading Loading @@ -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); } } } } Loading