diff options
-rw-r--r-- | core/java/android/os/FileUtils.java | 56 | ||||
-rw-r--r-- | media/java/android/media/ExifInterface.java | 17 | ||||
-rw-r--r-- | media/java/android/media/MediaMetadataRetriever.java | 25 | ||||
-rw-r--r-- | media/java/android/media/MediaPlayer.java | 25 | ||||
-rw-r--r-- | media/jni/android_media_MediaMetadataRetriever.cpp | 2 |
5 files changed, 118 insertions, 7 deletions
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 70c924a46c17..bbafc7b0875a 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -40,9 +40,16 @@ import static android.system.OsConstants.W_OK; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; +import android.app.AppGlobals; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ProviderInfo; +import android.content.res.AssetFileDescriptor; +import android.net.Uri; import android.provider.DocumentsContract.Document; +import android.provider.MediaStore; import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; @@ -118,6 +125,7 @@ public final class FileUtils { // non-final so it can be toggled by Robolectric's ShadowFileUtils private static boolean sEnableCopyOptimizations = true; + private static volatile int sMediaProviderAppId = -1; private static final long COPY_CHECKPOINT_BYTES = 524288; @@ -1425,6 +1433,54 @@ public final class FileUtils { } /** {@hide} */ + public static FileDescriptor convertToModernFd(FileDescriptor fd) { + try { + Context context = AppGlobals.getInitialApplication(); + if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) { + // Never convert modern fd for MediaProvider, because this requires + // MediaStore#scanFile and can cause infinite loops when MediaProvider scans + return null; + } + File realFile = ParcelFileDescriptor.getFile(fd); + Log.i(TAG, "Changing to modern format dataSource for: " + realFile); + ContentResolver resolver = context.getContentResolver(); + + Uri uri = MediaStore.scanFile(resolver, realFile); + if (uri != null) { + Bundle opts = new Bundle(); + // TODO(b/158465539): Use API constant + opts.putBoolean("android.provider.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) { + Log.w(TAG, "Failed to change to modern format dataSource"); + } + return null; + } + + private static int getMediaProviderAppId(Context context) { + if (sMediaProviderAppId != -1) { + return sMediaProviderAppId; + } + + PackageManager pm = context.getPackageManager(); + ProviderInfo provider = context.getPackageManager().resolveContentProvider( + MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE + | PackageManager.MATCH_SYSTEM_ONLY); + if (provider == null) { + return -1; + } + + sMediaProviderAppId = UserHandle.getAppId(provider.applicationInfo.uid); + return sMediaProviderAppId; + } + + /** {@hide} */ @VisibleForTesting public static class MemoryPipe extends Thread implements AutoCloseable { private final FileDescriptor[] pipe; diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index f9cbdd42bc4f..44890bee2291 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -31,6 +31,8 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.os.FileUtils; +import android.os.SystemProperties; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -1523,6 +1525,11 @@ public class ExifInterface { if (fileDescriptor == null) { throw new NullPointerException("fileDescriptor cannot be null"); } + boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_exif_optimize", false); + FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fileDescriptor) : null; + if (modernFd != null) { + fileDescriptor = modernFd; + } mAssetInputStream = null; mFilename = null; @@ -2533,11 +2540,20 @@ public class ExifInterface { private void initForFilename(String filename) throws IOException { FileInputStream in = null; + FileInputStream legacyInputStream = null; mAssetInputStream = null; mFilename = filename; mIsInputStream = false; try { in = new FileInputStream(filename); + boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_exif_optimize", + false); + FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(in.getFD()) : null; + if (modernFd != null) { + legacyInputStream = in; + in = new FileInputStream(modernFd); + } + if (isSeekableFD(in.getFD())) { mSeekableFileDescriptor = in.getFD(); } else { @@ -2546,6 +2562,7 @@ public class ExifInterface { loadAttributes(in); } finally { closeQuietly(in); + closeQuietly(legacyInputStream); } } diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 835a7091bb70..ca8b9b936e99 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -30,7 +30,10 @@ import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; +import android.os.Bundle; +import android.os.FileUtils; import android.os.IBinder; +import android.os.SystemProperties; import android.text.TextUtils; import java.io.FileDescriptor; @@ -48,7 +51,6 @@ import java.util.Map; * frame and meta data from an input media file. */ public class MediaMetadataRetriever implements AutoCloseable { - // borrowed from ExoPlayer private static final String[] STANDARD_GENRES = new String[] { // These are the official ID3v1 genres. @@ -296,7 +298,19 @@ public class MediaMetadataRetriever implements AutoCloseable { * non-negative. * @throws IllegalArgumentException if the arguments are invalid */ - public native void setDataSource(FileDescriptor fd, long offset, long length) + public void setDataSource(FileDescriptor fd, long offset, long length) + throws IllegalArgumentException { + boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_retriever_optimize", + false); + FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fd) : null; + if (modernFd == null) { + _setDataSource(fd, offset, length); + } else { + _setDataSource(modernFd, offset, length); + } + } + + private native void _setDataSource(FileDescriptor fd, long offset, long length) throws IllegalArgumentException; /** @@ -340,7 +354,12 @@ public class MediaMetadataRetriever implements AutoCloseable { try { ContentResolver resolver = context.getContentResolver(); try { - fd = resolver.openAssetFileDescriptor(uri, "r"); + boolean optimize = + SystemProperties.getBoolean("fuse.sys.transcode_retriever_optimize", false); + Bundle opts = new Bundle(); + opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true); + fd = optimize ? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts) + : resolver.openAssetFileDescriptor(uri, "r"); } catch(FileNotFoundException e) { throw new IllegalArgumentException("could not access " + uri); } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 851c1ec8ec1f..47d276a50034 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -31,6 +31,8 @@ import android.graphics.SurfaceTexture; import android.media.SubtitleController.Anchor; import android.media.SubtitleTrack.RenderingWidget; import android.net.Uri; +import android.os.Bundle; +import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -1104,7 +1106,13 @@ public class MediaPlayer extends PlayerBase } private boolean attemptDataSource(ContentResolver resolver, Uri uri) { - try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) { + boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_player_optimize", + false); + Bundle opts = new Bundle(); + opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true); + try (AssetFileDescriptor afd = optimize + ? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts) + : resolver.openAssetFileDescriptor(uri, "r")) { setDataSource(afd); return true; } catch (NullPointerException | SecurityException | IOException ex) { @@ -1245,7 +1253,13 @@ public class MediaPlayer extends PlayerBase */ public void setDataSource(FileDescriptor fd, long offset, long length) throws IOException, IllegalArgumentException, IllegalStateException { - _setDataSource(fd, offset, length); + boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_player_optimize", false); + FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fd) : null; + if (modernFd == null) { + _setDataSource(fd, offset, length); + } else { + _setDataSource(modernFd, offset, length); + } } private native void _setDataSource(FileDescriptor fd, long offset, long length) @@ -2899,8 +2913,13 @@ public class MediaPlayer extends PlayerBase AssetFileDescriptor fd = null; try { + boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_player_optimize", + false); ContentResolver resolver = context.getContentResolver(); - fd = resolver.openAssetFileDescriptor(uri, "r"); + Bundle opts = new Bundle(); + opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true); + fd = optimize ? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts) + : resolver.openAssetFileDescriptor(uri, "r"); if (fd == null) { return; } diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 6fbd29cb8623..126897a908f8 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -704,7 +704,7 @@ static const JNINativeMethod nativeMethods[] = { (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders }, - {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", + {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD}, {"_setDataSource", "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback}, |