Merge changes I1a2b9958,I534ac743,I9e50bb3a into rvc-dev
* changes:
Update database for apps bypassing scoped storage restrictions
Grant concession for FileManager and SystemGallery
Insert database row for apps bypassing scoped storage
diff --git a/deploy.sh b/deploy.sh
index 22524c0..e6edcce 100755
--- a/deploy.sh
+++ b/deploy.sh
@@ -8,6 +8,7 @@
adb remount
adb sync
adb shell umount /apex/com.android.mediaprovider*
+adb shell setprop apexd.status '""'
adb shell setprop ctl.restart apexd
adb shell rm -rf /system/priv-app/MediaProvider
adb shell rm -rf /system/priv-app/MediaProviderGoogle
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 63015bd..7f95186 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -1554,7 +1554,7 @@
return active.load(std::memory_order_acquire);
}
-void FuseDaemon::Start(const int fd, const std::string& path) {
+void FuseDaemon::Start(android::base::unique_fd fd, const std::string& path) {
struct fuse_args args;
struct fuse_cmdline_opts opts;
diff --git a/jni/FuseDaemon.h b/jni/FuseDaemon.h
index d9925d4..3c4b947 100644
--- a/jni/FuseDaemon.h
+++ b/jni/FuseDaemon.h
@@ -20,6 +20,8 @@
#include <memory>
#include <string>
+#include <android-base/unique_fd.h>
+
#include "MediaProviderWrapper.h"
#include "jni.h"
@@ -35,7 +37,7 @@
/**
* Start the FUSE daemon loop that will handle filesystem calls.
*/
- void Start(const int fd, const std::string& path);
+ void Start(android::base::unique_fd fd, const std::string& path);
/**
* Checks if the FUSE daemon is started.
diff --git a/jni/com_android_providers_media_FuseDaemon.cpp b/jni/com_android_providers_media_FuseDaemon.cpp
index ae1c175..3a65696 100644
--- a/jni/com_android_providers_media_FuseDaemon.cpp
+++ b/jni/com_android_providers_media_FuseDaemon.cpp
@@ -24,6 +24,7 @@
#include "FuseDaemon.h"
#include "MediaProviderWrapper.h"
#include "android-base/logging.h"
+#include "android-base/unique_fd.h"
namespace mediaprovider {
namespace {
@@ -42,12 +43,14 @@
LOG(DEBUG) << "Starting the FUSE daemon...";
fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
+ android::base::unique_fd ufd(fd);
+
ScopedUtfChars utf_chars_path(env, java_path);
if (!utf_chars_path.c_str()) {
return;
}
- daemon->Start(fd, utf_chars_path.c_str());
+ daemon->Start(std::move(ufd), utf_chars_path.c_str());
}
bool com_android_providers_media_FuseDaemon_is_started(JNIEnv* env, jobject self,
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 3265df1..952f895 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -4019,19 +4019,19 @@
*/
private int deleteRecursive(SQLiteQueryBuilder qb, DatabaseHelper helper, String userWhere,
String[] userWhereArgs) {
- synchronized (mDirectoryCache) {
- mDirectoryCache.clear();
+ return (int) helper.runWithTransaction((db) -> {
+ synchronized (mDirectoryCache) {
+ mDirectoryCache.clear();
+ }
- return (int) helper.runWithTransaction((db) -> {
- int n = 0;
- int total = 0;
- do {
- n = qb.delete(helper, userWhere, userWhereArgs);
- total += n;
- } while (n > 0);
- return total;
- });
- }
+ int n = 0;
+ int total = 0;
+ do {
+ n = qb.delete(helper, userWhere, userWhereArgs);
+ total += n;
+ } while (n > 0);
+ return total;
+ });
}
@Override
@@ -4384,7 +4384,7 @@
// doesn't exist we fall through to create it below
final File thumbFile = getThumbnailFile(uri);
try {
- return ParcelFileDescriptor.open(thumbFile,
+ return FileUtils.openSafely(thumbFile,
ParcelFileDescriptor.MODE_READ_ONLY);
} catch (FileNotFoundException ignored) {
}
@@ -4407,9 +4407,9 @@
// once for remote reading. Both FDs point at the same
// underlying inode on disk, so they're stable across renames
// to avoid race conditions between threads.
- thumbWrite = ParcelFileDescriptor.open(thumbTempFile,
+ thumbWrite = FileUtils.openSafely(thumbTempFile,
ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE);
- thumbRead = ParcelFileDescriptor.open(thumbTempFile,
+ thumbRead = FileUtils.openSafely(thumbTempFile,
ParcelFileDescriptor.MODE_READ_ONLY);
final Bitmap thumbnail = getThumbnailBitmap(uri, signal);
@@ -4828,15 +4828,6 @@
// Make sure any updated paths look sane
assertFileColumnsSane(match, uri, initialValues);
- // if the media type is being changed, check if it's being changed from image or video
- // to something else
- if (initialValues.containsKey(FileColumns.MEDIA_TYPE)) {
- final int newMediaType = initialValues.getAsInteger(FileColumns.MEDIA_TYPE);
-
- // If we're changing media types, invalidate any thumbnails
- triggerInvalidate = true;
- }
-
if (initialValues.containsKey(FileColumns.DATA)) {
// If we're changing paths, invalidate any thumbnails
triggerInvalidate = true;
@@ -4861,11 +4852,7 @@
final ContentValues values = new ContentValues(initialValues);
switch (match) {
- case AUDIO_MEDIA_ID: {
- computeAudioLocalizedValues(values);
- computeAudioKeyValues(values);
- // fall-through
- }
+ case AUDIO_MEDIA_ID:
case AUDIO_PLAYLISTS_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
@@ -4876,6 +4863,17 @@
}
}
+ if (initialValues.containsKey(FileColumns.MEDIA_TYPE)) {
+ final int mediaType = initialValues.getAsInteger(FileColumns.MEDIA_TYPE);
+ switch (mediaType) {
+ case FileColumns.MEDIA_TYPE_AUDIO: {
+ computeAudioLocalizedValues(values);
+ computeAudioKeyValues(values);
+ break;
+ }
+ }
+ }
+
count = qb.update(helper, values, userWhere, userWhereArgs);
// If the caller tried (and failed) to update metadata, the file on disk
@@ -5520,7 +5518,7 @@
// If fuse is enabled, we can provide an fd that points to the fuse
// file system and handle redaction in the fuse handler when the caller reads.
Log.i(TAG, "Redacting with new FUSE for " + filePath);
- pfd = ParcelFileDescriptor.open(getFuseFile(file), modeBits);
+ pfd = FileUtils.openSafely(getFuseFile(file), modeBits);
} else {
// TODO(b/135341978): Remove this and associated code
// when fuse is on by default.
@@ -5538,7 +5536,7 @@
daemon = getFuseDaemonForFile(file);
} catch (FileNotFoundException ignored) {
}
- ParcelFileDescriptor lowerFsFd = ParcelFileDescriptor.open(file, modeBits);
+ ParcelFileDescriptor lowerFsFd = FileUtils.openSafely(file, modeBits);
boolean forRead = (modeBits & ParcelFileDescriptor.MODE_READ_ONLY) != 0;
boolean shouldOpenWithFuse = daemon != null
&& daemon.shouldOpenWithFuse(filePath, forRead, lowerFsFd.getFd());
@@ -5549,7 +5547,7 @@
// resulting from cache inconsistencies between the upper and lower
// filesystem caches
Log.w(TAG, "Using FUSE for " + filePath);
- pfd = ParcelFileDescriptor.open(getFuseFile(file), modeBits);
+ pfd = FileUtils.openSafely(getFuseFile(file), modeBits);
try {
lowerFsFd.close();
} catch (IOException e) {
diff --git a/src/com/android/providers/media/fuse/FuseDaemon.java b/src/com/android/providers/media/fuse/FuseDaemon.java
index 95a160b..3b7a0f8 100644
--- a/src/com/android/providers/media/fuse/FuseDaemon.java
+++ b/src/com/android/providers/media/fuse/FuseDaemon.java
@@ -151,7 +151,10 @@
}
private native long native_new(MediaProvider mediaProvider);
+
+ // Takes ownership of the passed in file descriptor!
private native void native_start(long daemon, int deviceFd, String path);
+
private native void native_delete(long daemon);
private native boolean native_should_open_with_fuse(long daemon, String path, boolean readLock,
int fd);
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index 6b0cd80..e711d0c 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -25,12 +25,16 @@
import static android.system.OsConstants.F_OK;
import static android.system.OsConstants.O_ACCMODE;
import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CLOEXEC;
import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_NOFOLLOW;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.O_TRUNC;
import static android.system.OsConstants.O_WRONLY;
import static android.system.OsConstants.R_OK;
+import static android.system.OsConstants.S_IRWXG;
+import static android.system.OsConstants.S_IRWXU;
import static android.system.OsConstants.W_OK;
import static com.android.providers.media.util.DatabaseUtils.getAsBoolean;
@@ -43,9 +47,13 @@
import android.content.Context;
import android.net.Uri;
import android.os.Environment;
+import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
@@ -56,6 +64,7 @@
import androidx.annotation.VisibleForTesting;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -80,10 +89,39 @@
import java.util.regex.Pattern;
public class FileUtils {
+ /**
+ * Drop-in replacement for {@link ParcelFileDescriptor#open(File, int)}
+ * which adds security features like {@link OsConstants#O_CLOEXEC} and
+ * {@link OsConstants#O_NOFOLLOW}.
+ */
+ public static @NonNull ParcelFileDescriptor openSafely(@NonNull File file, int pfdFlags)
+ throws FileNotFoundException {
+ final int posixFlags = translateModePfdToPosix(pfdFlags) | O_CLOEXEC | O_NOFOLLOW;
+ try {
+ final FileDescriptor fd = Os.open(file.getAbsolutePath(), posixFlags,
+ S_IRWXU | S_IRWXG);
+ try {
+ return ParcelFileDescriptor.dup(fd);
+ } finally {
+ closeQuietly(fd);
+ }
+ } catch (IOException | ErrnoException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ }
+
public static void closeQuietly(@Nullable AutoCloseable closeable) {
android.os.FileUtils.closeQuietly(closeable);
}
+ public static void closeQuietly(@Nullable FileDescriptor fd) {
+ if (fd == null) return;
+ try {
+ Os.close(fd);
+ } catch (ErrnoException ignored) {
+ }
+ }
+
public static long copy(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {
return android.os.FileUtils.copy(in, out);
}
diff --git a/src/com/android/providers/media/util/RedactingFileDescriptor.java b/src/com/android/providers/media/util/RedactingFileDescriptor.java
index a0bec59..bf2524f 100644
--- a/src/com/android/providers/media/util/RedactingFileDescriptor.java
+++ b/src/com/android/providers/media/util/RedactingFileDescriptor.java
@@ -47,15 +47,10 @@
private volatile long[] mRedactRanges;
private volatile long[] mFreeOffsets;
- private FileDescriptor mInner = null;
+ private ParcelFileDescriptor mInner = null;
private ParcelFileDescriptor mOuter = null;
- public static void closeQuietly(FileDescriptor fd) {
- try {
- Os.close(fd);
- } catch (ErrnoException ignored) {
- }
- }
+ private FileDescriptor mInnerFd = null;
private RedactingFileDescriptor(
Context context, File file, int mode, long[] redactRanges, long[] freeOffsets)
@@ -64,17 +59,13 @@
mFreeOffsets = freeOffsets;
try {
- try {
- mInner = Os.open(file.getAbsolutePath(),
- FileUtils.translateModePfdToPosix(mode), 0);
- mOuter = context.getSystemService(StorageManager.class)
- .openProxyFileDescriptor(mode, mCallback,
- new Handler(Looper.getMainLooper()));
- } catch (ErrnoException e) {
- throw e.rethrowAsIOException();
- }
+ mInner = FileUtils.openSafely(file, mode);
+ mInnerFd = mInner.getFileDescriptor();
+ mOuter = context.getSystemService(StorageManager.class)
+ .openProxyFileDescriptor(mode, mCallback,
+ new Handler(Looper.getMainLooper()));
} catch (IOException e) {
- closeQuietly(mInner);
+ FileUtils.closeQuietly(mInner);
FileUtils.closeQuietly(mOuter);
throw e;
}
@@ -158,7 +149,7 @@
private final ProxyFileDescriptorCallback mCallback = new ProxyFileDescriptorCallback() {
@Override
public long onGetSize() throws ErrnoException {
- return Os.fstat(mInner).st_size;
+ return Os.fstat(mInnerFd).st_size;
}
@Override
@@ -166,7 +157,7 @@
int n = 0;
while (n < size) {
try {
- final int res = Os.pread(mInner, data, n, size - n, offset + n);
+ final int res = Os.pread(mInnerFd, data, n, size - n, offset + n);
if (res == 0) {
break;
} else {
@@ -203,7 +194,7 @@
int n = 0;
while (n < size) {
try {
- final int res = Os.pwrite(mInner, data, n, size - n, offset + n);
+ final int res = Os.pwrite(mInnerFd, data, n, size - n, offset + n);
if (res == 0) {
break;
} else {
@@ -222,12 +213,12 @@
@Override
public void onFsync() throws ErrnoException {
- Os.fsync(mInner);
+ Os.fsync(mInnerFd);
}
@Override
public void onRelease() {
- closeQuietly(mInner);
+ FileUtils.closeQuietly(mInner);
}
};
}