diff options
author | Marco Nelissen <marcone@google.com> | 2017-11-07 13:52:02 -0800 |
---|---|---|
committer | Tim Schumacher <timschumi@gmx.de> | 2018-06-19 19:33:06 +0200 |
commit | 63cbf29d4faf621127e618e86b2d6ed7012fc781 (patch) | |
tree | 6dbe7dfbe5b189ea1298b706b4e7ea2d299a23f8 | |
parent | 59941bdc226a2b779613701f221f76d65ffa40ba (diff) | |
download | frameworks_base-63cbf29d4faf621127e618e86b2d6ed7012fc781.tar.gz frameworks_base-63cbf29d4faf621127e618e86b2d6ed7012fc781.tar.bz2 frameworks_base-63cbf29d4faf621127e618e86b2d6ed7012fc781.zip |
Rework thumbnail cleanup
Bug: 63766886
Test: ran CTS tests
Change-Id: I1f92bb014e275eafe3f42aef1f8c817f187c6608
(cherry picked from commit 6d2096f3889d38da60099b1b5678347de4f042bf)
CVE-2018-9379
-rw-r--r-- | core/java/android/provider/MediaStore.java | 4 | ||||
-rw-r--r-- | media/java/android/media/MediaScanner.java | 53 | ||||
-rw-r--r-- | media/java/android/media/MiniThumbFile.java | 54 |
3 files changed, 54 insertions, 57 deletions
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 48b3c1a1b06..cdd7d1fb42f 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -672,8 +672,8 @@ public final class MediaStore { // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo); // If the magic is non-zero, we simply return thumbnail if it does exist. // querying MediaProvider and simply return thumbnail. - MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI - : Images.Media.EXTERNAL_CONTENT_URI); + MiniThumbFile thumbFile = MiniThumbFile.instance( + isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI); Cursor c = null; try { long magic = thumbFile.getMagic(origId); diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 9264bc0c4b6..80a4c4b407d 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -313,7 +313,6 @@ public class MediaScanner private Uri mAudioUri; private Uri mVideoUri; private Uri mImagesUri; - private Uri mThumbsUri; private Uri mPlaylistsUri; private Uri mFilesUri; private Uri mFilesUriNoNotify; @@ -1276,54 +1275,6 @@ public class MediaScanner return false; } - private void pruneDeadThumbnailFiles() { - HashSet<String> existingFiles = new HashSet<String>(); - String directory = "/sdcard/DCIM/.thumbnails"; - String [] files = (new File(directory)).list(); - Cursor c = null; - if (files == null) - files = new String[0]; - - for (int i = 0; i < files.length; i++) { - String fullPathString = directory + "/" + files[i]; - existingFiles.add(fullPathString); - } - - try { - c = mMediaProvider.query( - mPackageName, - mThumbsUri, - new String [] { "_data" }, - null, - null, - null, null); - Log.v(TAG, "pruneDeadThumbnailFiles... " + c); - if (c != null && c.moveToFirst()) { - do { - String fullPathString = c.getString(0); - existingFiles.remove(fullPathString); - } while (c.moveToNext()); - } - - for (String fileToDelete : existingFiles) { - if (false) - Log.v(TAG, "fileToDelete is " + fileToDelete); - try { - (new File(fileToDelete)).delete(); - } catch (SecurityException ex) { - } - } - - Log.v(TAG, "/pruneDeadThumbnailFiles... " + c); - } catch (RemoteException e) { - // We will soon be killed... - } finally { - if (c != null) { - c.close(); - } - } - } - static class MediaBulkDeleter { StringBuilder whereClause = new StringBuilder(); ArrayList<String> whereArgs = new ArrayList<String>(100); @@ -1369,9 +1320,6 @@ public class MediaScanner processPlayLists(); } - if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external"))) - pruneDeadThumbnailFiles(); - // allow GC to clean up mPlayLists = null; mMediaProvider = null; @@ -1391,7 +1339,6 @@ public class MediaScanner mAudioUri = Audio.Media.getContentUri(volumeName); mVideoUri = Video.Media.getContentUri(volumeName); mImagesUri = Images.Media.getContentUri(volumeName); - mThumbsUri = Images.Thumbnails.getContentUri(volumeName); mFilesUri = Files.getContentUri(volumeName); mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build(); diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java index 664308c45bf..98993676ce4 100644 --- a/media/java/android/media/MiniThumbFile.java +++ b/media/java/android/media/MiniThumbFile.java @@ -44,13 +44,14 @@ import java.util.Hashtable; */ public class MiniThumbFile { private static final String TAG = "MiniThumbFile"; - private static final int MINI_THUMB_DATA_FILE_VERSION = 3; + private static final int MINI_THUMB_DATA_FILE_VERSION = 4; public static final int BYTES_PER_MINTHUMB = 10000; private static final int HEADER_SIZE = 1 + 8 + 4; private Uri mUri; private RandomAccessFile mMiniThumbFile; private FileChannel mChannel; private ByteBuffer mBuffer; + private ByteBuffer mEmptyBuffer; private static final Hashtable<String, MiniThumbFile> sThumbFiles = new Hashtable<String, MiniThumbFile>(); @@ -127,9 +128,10 @@ public class MiniThumbFile { return mMiniThumbFile; } - public MiniThumbFile(Uri uri) { + private MiniThumbFile(Uri uri) { mUri = uri; mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); + mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); } public synchronized void deactivate() { @@ -184,6 +186,54 @@ public class MiniThumbFile { return 0; } + public synchronized void eraseMiniThumb(long id) { + RandomAccessFile r = miniThumbDataFile(); + if (r != null) { + long pos = id * BYTES_PER_MINTHUMB; + FileLock lock = null; + try { + mBuffer.clear(); + mBuffer.limit(1 + 8); + + lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false); + // check that we can read the following 9 bytes + // (1 for the "status" and 8 for the long) + if (mChannel.read(mBuffer, pos) == 9) { + mBuffer.position(0); + if (mBuffer.get() == 1) { + long currentMagic = mBuffer.getLong(); + if (currentMagic == 0) { + // there is no thumbnail stored here + Log.i(TAG, "no thumbnail for id " + id); + return; + } + // zero out the thumbnail slot + // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic + // + " at offset " + pos); + mChannel.write(mEmptyBuffer, pos); + } + } else { + // Log.v(TAG, "No slot"); + } + } catch (IOException ex) { + Log.v(TAG, "Got exception checking file magic: ", ex); + } catch (RuntimeException ex) { + // Other NIO related exception like disk full, read only channel..etc + Log.e(TAG, "Got exception when reading magic, id = " + id + + ", disk full or mount read-only? " + ex.getClass()); + } finally { + try { + if (lock != null) lock.release(); + } + catch (IOException ex) { + // ignore it. + } + } + } else { + // Log.v(TAG, "No data file"); + } + } + public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic) throws IOException { RandomAccessFile r = miniThumbDataFile(); |