@Override public ParcelFileDescriptor openDocument( String documentId, String mode, CancellationSignal signal) throws FileNotFoundException { final File file = getFileForDocId(documentId); final File visibleFile = getFileForDocId(documentId, true); final int pfdMode = ParcelFileDescriptor.parseMode(mode); if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY || visibleFile == null) { return ParcelFileDescriptor.open(file, pfdMode); } else { try { // When finished writing, kick off media scanner return ParcelFileDescriptor.open( file, pfdMode, mHandler, new OnCloseListener() { @Override public void onClose(IOException e) { final Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(visibleFile)); getContext().sendBroadcast(intent); } }); } catch (IOException e) { throw new FileNotFoundException("Failed to open for writing: " + e); } } }
@NonNull private ParcelFileDescriptor safeOpenFileHelper(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { Cursor c = query(uri, new String[] {"_data"}, null, null, null); int count = (c != null) ? c.getCount() : 0; if (count != 1) { // If there is not exactly one result, throw an appropriate // exception. if (c != null) { c.close(); } if (count == 0) { throw new FileNotFoundException("No entry for " + uri); } throw new FileNotFoundException("Multiple items at " + uri); } c.moveToFirst(); int i = c.getColumnIndex("_data"); String path = (i >= 0 ? c.getString(i) : null); c.close(); if (path == null) { throw new FileNotFoundException("Column _data not found."); } File filePath = new File(path); try { // The MmsProvider shouldn't open a file that isn't MMS data, so we verify that the // _data path actually points to MMS data. That safeguards ourselves from callers who // inserted or updated a URI (more specifically the _data column) with disallowed paths. // TODO(afurtado): provide a more robust mechanism to avoid disallowed _data paths to // be inserted/updated in the first place, including via SQL injection. if (!filePath .getCanonicalPath() .startsWith(getContext().getDir(PARTS_DIR_NAME, 0).getCanonicalPath())) { Log.e( TAG, "openFile: path " + filePath.getCanonicalPath() + " does not start with " + getContext().getDir(PARTS_DIR_NAME, 0).getCanonicalPath()); // Don't care return value return null; } } catch (IOException e) { Log.e(TAG, "openFile: create path failed " + e, e); return null; } int modeBits = ParcelFileDescriptor.parseMode(mode); return ParcelFileDescriptor.open(filePath, modeBits); }