summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2018-05-01 10:01:52 -0600
committerJeff Sharkey <jsharkey@android.com>2018-05-01 10:03:18 -0600
commitb00d5ea59a5218cde5d7b2e84572f6fd26611f25 (patch)
tree15859f855b7a3c2cfe7e1c770aa0cce1d5a4c219
parent68f36d6b5d5ad4711811160795cab399d247845d (diff)
Return to modifying raw /mnt/media_rw paths.
We thought we could push everyone through sdcardfs, but secondary devices mounted in a stable location don't give full write access to apps holding WRITE_EXTERNAL_STORAGE, so system internals still need to reach behind sdcardfs. To keep sdcardfs in the loop about changes that we make behind its back, we issue access(2) calls which should be enough for it to invalidate any cached details. Bug: 74132243 Test: manual Change-Id: I727cd179a5a825b16ec4df6e2f41a079758d41c5
-rw-r--r--core/java/android/os/storage/VolumeInfo.java2
-rw-r--r--core/java/com/android/internal/content/FileSystemProvider.java28
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java29
3 files changed, 50 insertions, 9 deletions
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 9e3e386eedb2..5c99f6c87d7c 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -312,7 +312,7 @@ public class VolumeInfo implements Parcelable {
* {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
*/
public File getInternalPathForUser(int userId) {
- if (type == TYPE_PUBLIC && !isVisible()) {
+ if (type == TYPE_PUBLIC) {
// TODO: plumb through cleaner path from vold
return new File(path.replace("/storage/", "/mnt/media_rw/"));
} else {
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index a075705c2e40..b591163e8728 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -85,6 +85,14 @@ public abstract class FileSystemProvider extends DocumentsProvider {
protected abstract Uri buildNotificationUri(String docId);
+ /**
+ * Callback indicating that the given document has been modified. This gives
+ * the provider a hook to invalidate cached data, such as {@code sdcardfs}.
+ */
+ protected void onDocIdChanged(String docId) {
+ // Default is no-op
+ }
+
@Override
public boolean onCreate() {
throw new UnsupportedOperationException(
@@ -185,6 +193,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new IllegalStateException("Failed to mkdir " + file);
}
childId = getDocIdForFile(file);
+ onDocIdChanged(childId);
addFolderToMediaStore(getFileForDocId(childId, true));
} else {
try {
@@ -192,6 +201,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new IllegalStateException("Failed to touch " + file);
}
childId = getDocIdForFile(file);
+ onDocIdChanged(childId);
} catch (IOException e) {
throw new IllegalStateException("Failed to touch " + file + ": " + e);
}
@@ -227,16 +237,20 @@ public abstract class FileSystemProvider extends DocumentsProvider {
final File before = getFileForDocId(docId);
final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
- final File visibleFileBefore = getFileForDocId(docId, true);
if (!before.renameTo(after)) {
throw new IllegalStateException("Failed to rename to " + after);
}
final String afterDocId = getDocIdForFile(after);
- moveInMediaStore(visibleFileBefore, getFileForDocId(afterDocId, true));
+ onDocIdChanged(docId);
+ onDocIdChanged(afterDocId);
+
+ final File beforeVisibleFile = getFileForDocId(docId, true);
+ final File afterVisibleFile = getFileForDocId(afterDocId, true);
+ moveInMediaStore(beforeVisibleFile, afterVisibleFile);
if (!TextUtils.equals(docId, afterDocId)) {
- scanFile(after);
+ scanFile(afterVisibleFile);
return afterDocId;
} else {
return null;
@@ -259,6 +273,8 @@ public abstract class FileSystemProvider extends DocumentsProvider {
}
final String docId = getDocIdForFile(after);
+ onDocIdChanged(sourceDocumentId);
+ onDocIdChanged(docId);
moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true));
return docId;
@@ -308,6 +324,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
throw new IllegalStateException("Failed to delete " + file);
}
+ onDocIdChanged(docId);
removeFromMediaStore(visibleFile, isDirectory);
}
@@ -418,7 +435,10 @@ public abstract class FileSystemProvider extends DocumentsProvider {
try {
// When finished writing, kick off media scanner
return ParcelFileDescriptor.open(
- file, pfdMode, mHandler, (IOException e) -> scanFile(visibleFile));
+ file, pfdMode, mHandler, (IOException e) -> {
+ onDocIdChanged(documentId);
+ scanFile(visibleFile);
+ });
} catch (IOException e) {
throw new FileNotFoundException("Failed to open for writing: " + e);
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 2a82fc9b28df..0a720a5b234e 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -38,6 +38,9 @@ import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Path;
import android.provider.DocumentsContract.Root;
import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DebugUtils;
@@ -360,14 +363,19 @@ public class ExternalStorageProvider extends FileSystemProvider {
@Override
protected File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
+ return getFileForDocId(docId, visible, true);
+ }
+
+ private File getFileForDocId(String docId, boolean visible, boolean mustExist)
+ throws FileNotFoundException {
RootInfo root = getRootFromDocId(docId);
- return buildFile(root, docId, visible);
+ return buildFile(root, docId, visible, mustExist);
}
private Pair<RootInfo, File> resolveDocId(String docId, boolean visible)
throws FileNotFoundException {
RootInfo root = getRootFromDocId(docId);
- return Pair.create(root, buildFile(root, docId, visible));
+ return Pair.create(root, buildFile(root, docId, visible, true));
}
private RootInfo getRootFromDocId(String docId) throws FileNotFoundException {
@@ -385,7 +393,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
return root;
}
- private File buildFile(RootInfo root, String docId, boolean visible)
+ private File buildFile(RootInfo root, String docId, boolean visible, boolean mustExist)
throws FileNotFoundException {
final int splitIndex = docId.indexOf(':', 1);
final String path = docId.substring(splitIndex + 1);
@@ -398,7 +406,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
target.mkdirs();
}
target = new File(target, path);
- if (!target.exists()) {
+ if (mustExist && !target.exists()) {
throw new FileNotFoundException("Missing file for " + docId + " at " + target);
}
return target;
@@ -410,6 +418,19 @@ public class ExternalStorageProvider extends FileSystemProvider {
}
@Override
+ protected void onDocIdChanged(String docId) {
+ try {
+ // Touch the visible path to ensure that any sdcardfs caches have
+ // been updated to reflect underlying changes on disk.
+ final File visiblePath = getFileForDocId(docId, true, false);
+ if (visiblePath != null) {
+ Os.access(visiblePath.getAbsolutePath(), OsConstants.F_OK);
+ }
+ } catch (FileNotFoundException | ErrnoException ignored) {
+ }
+ }
+
+ @Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
synchronized (mRootsLock) {