summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/os/FileUtils.java56
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;