問題描述
在 Android 中持久化文件描述符 (Persisting File Descriptors in Android)
I am writing an Android app that manages files and shares them with other applications. The application implements a content provider that hands out ParcelFileDescriptor
objects to requesting applications (just like the built in Email app and K-9 Mail applications do):
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
File file;
...
file = new File(FilePermsActivity.FILE_ROOT, fileName);
ParcelFileDescriptor fd;
fd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
// store the file descriptor for later
String callerPackage = getAppNameByPID(getContext(), Binder.getCallingPid());
FilesApplication.getInstance().addFd(callerPackage, fd);
return fd;
}
I want to allow the file manager to close the file descriptors later to prevent two applications from holding open read+write file descriptors at once. The FilesApplication
class does that, storing the ParcelFileDescriptor
objects for later use:
public void addFd(String packageName, ParcelFileDescriptor fd) {
List<ParcelFileDescriptor> fds = null;
if ( openFds.containsKey(packageName))
{
fds = openFds.get(packageName);
fds.add(fd);
}
else
{
fds = new ArrayList<ParcelFileDescriptor>();
fds.add(fd);
openFds.put(packageName, fds);
}
}
public List<ParcelFileDescriptor> getFds (String packageName) {
return openFds.get(packageName);
}
The problem is that when I try to retrieve the open ParcelFileDescriptor
s using the getFds
, the file descriptor is always invalid. From checking, the recipient application can still use the file descriptor sent before, but my application isn't able to close it.
Is there something preventing the storage in an ArrayList
and subsequent retrieval of file descriptors?
參考解法
方法 1:
After more searching, the problem isn't the ParcelFileDescriptor
since no matter which container I used to hold it (ArrayList
, regular ParcelFileDescriptor[]
), it got invalidated. The best explanation I can find is that the documentation for ContentProvider says:
The returned ParcelFileDescriptor is owned by the caller, so it is their responsibility to close it when done. That is, the implementation of this method should create a new ParcelFileDescriptor for each call.
I guess that means that the caller gets exclusive control over the returned file descriptor and my application can't later close it.