diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/os/FileUtils.java | 56 |
1 files changed, 56 insertions, 0 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; |
