Loading core/java/android/os/FileUtils.java +17 −4 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.Locale; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; Loading Loading @@ -115,6 +116,9 @@ public final class FileUtils { private FileUtils() { } private static final String CAMERA_DIR_LOWER_CASE = "/storage/emulated/" + UserHandle.myUserId() + "/dcim/camera"; /** Regular expression for safe filenames: no spaces or metacharacters. * * Use a preload holder so that FileUtils can be compile-time initialized. Loading Loading @@ -1432,18 +1436,27 @@ public final class FileUtils { } } // TODO(b/170488060): Consider better approach /** {@hide} */ @VisibleForTesting public static FileDescriptor convertToModernFd(FileDescriptor fd) { try { Context context = AppGlobals.getInitialApplication(); File realFile = ParcelFileDescriptor.getFile(fd); String fileName = realFile.getName(); boolean isCameraVideo = !fileName.startsWith(".") && fileName.endsWith(".mp4") && contains(CAMERA_DIR_LOWER_CASE, realFile.getAbsolutePath().toLowerCase( Locale.ROOT)); if (!SystemProperties.getBoolean("sys.fuse.transcode_enabled", false) || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) { // If transcode is enabled we optimize by default, unless explicitly disabled. // Never convert modern fd for MediaProvider, because this requires || 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 // 3. Only convert published mp4 videos in the DCIM/Camera dir return null; } File realFile = ParcelFileDescriptor.getFile(fd); Log.i(TAG, "Changing to modern format dataSource for: " + realFile); ContentResolver resolver = context.getContentResolver(); Loading core/tests/coretests/src/android/os/FileUtilsTest.java +53 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.os; import static android.os.FileUtils.convertToModernFd; import static android.os.FileUtils.roundStorageSize; import static android.os.FileUtils.translateModeAccessToPosix; import static android.os.FileUtils.translateModePfdToPosix; Loading Loading @@ -45,6 +46,8 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; Loading @@ -67,6 +70,7 @@ import org.junit.runner.RunWith; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Arrays; Loading Loading @@ -562,6 +566,55 @@ public class FileUtilsTest { assertEquals(O_RDWR, translateModeAccessToPosix(R_OK | W_OK | X_OK)); } @Test public void testConvertToModernFd() throws Exception { final String nonce = String.valueOf(System.nanoTime()); final File cameraDir = new File("/storage/emulated/0/DCIM/Camera"); final File nonCameraDir = new File("/storage/emulated/0/Pictures"); cameraDir.mkdirs(); nonCameraDir.mkdirs(); final File validVideoCameraDir = new File(cameraDir, "validVideo-" + nonce + ".mp4"); final File validImageCameraDir = new File(cameraDir, "validImage-" + nonce + ".jpg"); final File invalidVideoCameraDir = new File(cameraDir, ".invalidVideo-" + nonce + ".mp4"); final File validVideoNonCameraDir = new File(nonCameraDir, "validVideo-" + nonce + ".mp4"); final File validImageNonCameraDir = new File(nonCameraDir, "validImage-" + nonce + ".jpg"); try { FileDescriptor pfdValidVideoCameraDir = ParcelFileDescriptor.open(validVideoCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdValidImageCameraDir = ParcelFileDescriptor.open(validImageCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdInvalidVideoCameraDir = ParcelFileDescriptor.open(invalidVideoCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdValidVideoNonCameraDir = ParcelFileDescriptor.open(validVideoNonCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdValidImageNonCameraDir = ParcelFileDescriptor.open(validImageNonCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); assertNotNull(convertToModernFd(pfdValidVideoCameraDir)); assertNull(convertToModernFd(pfdValidImageCameraDir)); assertNull(convertToModernFd(pfdInvalidVideoCameraDir)); assertNull(convertToModernFd(pfdValidVideoNonCameraDir)); assertNull(convertToModernFd(pfdValidImageNonCameraDir)); } finally { validVideoCameraDir.delete(); validImageCameraDir.delete(); invalidVideoCameraDir.delete(); validVideoNonCameraDir.delete(); validImageNonCameraDir.delete(); } } private static void assertTranslate(String string, int posix, int pfd) { assertEquals(posix, translateModeStringToPosix(string)); assertEquals(string, translateModePosixToString(posix)); Loading Loading
core/java/android/os/FileUtils.java +17 −4 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.Locale; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; Loading Loading @@ -115,6 +116,9 @@ public final class FileUtils { private FileUtils() { } private static final String CAMERA_DIR_LOWER_CASE = "/storage/emulated/" + UserHandle.myUserId() + "/dcim/camera"; /** Regular expression for safe filenames: no spaces or metacharacters. * * Use a preload holder so that FileUtils can be compile-time initialized. Loading Loading @@ -1432,18 +1436,27 @@ public final class FileUtils { } } // TODO(b/170488060): Consider better approach /** {@hide} */ @VisibleForTesting public static FileDescriptor convertToModernFd(FileDescriptor fd) { try { Context context = AppGlobals.getInitialApplication(); File realFile = ParcelFileDescriptor.getFile(fd); String fileName = realFile.getName(); boolean isCameraVideo = !fileName.startsWith(".") && fileName.endsWith(".mp4") && contains(CAMERA_DIR_LOWER_CASE, realFile.getAbsolutePath().toLowerCase( Locale.ROOT)); if (!SystemProperties.getBoolean("sys.fuse.transcode_enabled", false) || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) { // If transcode is enabled we optimize by default, unless explicitly disabled. // Never convert modern fd for MediaProvider, because this requires || 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 // 3. Only convert published mp4 videos in the DCIM/Camera dir return null; } File realFile = ParcelFileDescriptor.getFile(fd); Log.i(TAG, "Changing to modern format dataSource for: " + realFile); ContentResolver resolver = context.getContentResolver(); Loading
core/tests/coretests/src/android/os/FileUtilsTest.java +53 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.os; import static android.os.FileUtils.convertToModernFd; import static android.os.FileUtils.roundStorageSize; import static android.os.FileUtils.translateModeAccessToPosix; import static android.os.FileUtils.translateModePfdToPosix; Loading Loading @@ -45,6 +46,8 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; Loading @@ -67,6 +70,7 @@ import org.junit.runner.RunWith; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Arrays; Loading Loading @@ -562,6 +566,55 @@ public class FileUtilsTest { assertEquals(O_RDWR, translateModeAccessToPosix(R_OK | W_OK | X_OK)); } @Test public void testConvertToModernFd() throws Exception { final String nonce = String.valueOf(System.nanoTime()); final File cameraDir = new File("/storage/emulated/0/DCIM/Camera"); final File nonCameraDir = new File("/storage/emulated/0/Pictures"); cameraDir.mkdirs(); nonCameraDir.mkdirs(); final File validVideoCameraDir = new File(cameraDir, "validVideo-" + nonce + ".mp4"); final File validImageCameraDir = new File(cameraDir, "validImage-" + nonce + ".jpg"); final File invalidVideoCameraDir = new File(cameraDir, ".invalidVideo-" + nonce + ".mp4"); final File validVideoNonCameraDir = new File(nonCameraDir, "validVideo-" + nonce + ".mp4"); final File validImageNonCameraDir = new File(nonCameraDir, "validImage-" + nonce + ".jpg"); try { FileDescriptor pfdValidVideoCameraDir = ParcelFileDescriptor.open(validVideoCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdValidImageCameraDir = ParcelFileDescriptor.open(validImageCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdInvalidVideoCameraDir = ParcelFileDescriptor.open(invalidVideoCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdValidVideoNonCameraDir = ParcelFileDescriptor.open(validVideoNonCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); FileDescriptor pfdValidImageNonCameraDir = ParcelFileDescriptor.open(validImageNonCameraDir, MODE_CREATE | MODE_READ_WRITE).getFileDescriptor(); assertNotNull(convertToModernFd(pfdValidVideoCameraDir)); assertNull(convertToModernFd(pfdValidImageCameraDir)); assertNull(convertToModernFd(pfdInvalidVideoCameraDir)); assertNull(convertToModernFd(pfdValidVideoNonCameraDir)); assertNull(convertToModernFd(pfdValidImageNonCameraDir)); } finally { validVideoCameraDir.delete(); validImageCameraDir.delete(); invalidVideoCameraDir.delete(); validVideoNonCameraDir.delete(); validImageNonCameraDir.delete(); } } private static void assertTranslate(String string, int posix, int pfd) { assertEquals(posix, translateModeStringToPosix(string)); assertEquals(string, translateModePosixToString(posix)); Loading