Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d44efd7a authored by Marco Nelissen's avatar Marco Nelissen Committed by android-build-team Robot
Browse files

Rework thumbnail cleanup

Bug: 63766886
Test: ran CTS tests
Change-Id: I1f92bb014e275eafe3f42aef1f8c817f187c6608
(cherry picked from commit 6d2096f3)
parent dce05730
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -694,8 +694,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);
+0 −52
Original line number Diff line number Diff line
@@ -323,7 +323,6 @@ public class MediaScanner implements AutoCloseable {
    private final Uri mAudioUri;
    private final Uri mVideoUri;
    private final Uri mImagesUri;
    private final Uri mThumbsUri;
    private final Uri mPlaylistsUri;
    private final Uri mFilesUri;
    private final Uri mFilesUriNoNotify;
@@ -419,7 +418,6 @@ public class MediaScanner implements AutoCloseable {
        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();

@@ -1283,53 +1281,6 @@ public class MediaScanner implements AutoCloseable {
        }
    }

    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(
                    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);
@@ -1373,9 +1324,6 @@ public class MediaScanner implements AutoCloseable {
            processPlayLists();
        }

        if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
            pruneDeadThumbnailFiles();

        // allow GC to clean up
        mPlayLists.clear();
    }
+52 −2
Original line number Diff line number Diff line
@@ -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();