Skip to content

Commit

Permalink
Cancel any in-progress scans when media ejected.
Browse files Browse the repository at this point in the history
Bug: 117909601
Test: atest MediaProviderTests
Change-Id: I7bed0a6672f7c0b4a88dfb590d10b598997ad08d
  • Loading branch information
jsharkey committed Mar 22, 2019
1 parent 99a4828 commit 68b2f06
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/com/android/providers/media/IdleService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import android.content.ContentProviderClient;
import android.content.Context;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.provider.MediaStore;

import java.util.concurrent.TimeUnit;
Expand All @@ -40,6 +41,7 @@ public boolean onStartJob(JobParameters params) {
try (ContentProviderClient cpc = getContentResolver()
.acquireContentProviderClient(MediaStore.AUTHORITY)) {
((MediaProvider) cpc.getLocalContentProvider()).onIdleMaintenance(mSignal);
} catch (OperationCanceledException ignored) {
}
jobFinished(params, false);
}).start();
Expand Down
4 changes: 3 additions & 1 deletion src/com/android/providers/media/MediaProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
Expand Down Expand Up @@ -6022,6 +6021,9 @@ public void detachVolume(String volume) {
"Deleting the internal volume is not allowed");
}

// Signal any scanning to shut down
MediaScanner.instance(getContext()).onDetachVolume(volume);

synchronized (mDatabases) {
DatabaseHelper database = mDatabases.get(volume);
if (database == null) return;
Expand Down
5 changes: 5 additions & 0 deletions src/com/android/providers/media/scan/LegacyMediaScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,9 @@ public Uri scanFile(File file) {
Trace.traceEnd(Trace.TRACE_TAG_DATABASE);
}
}

@Override
public void onDetachVolume(String volumeName) {
// Ignored
}
}
1 change: 1 addition & 0 deletions src/com/android/providers/media/scan/MediaScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public interface MediaScanner {
public Context getContext();
public void scanDirectory(File file);
public Uri scanFile(File file);
public void onDetachVolume(String volumeName);

public static MediaScanner instance(Context context) {
if (MediaProvider.ENABLE_MODERN_SCANNER) {
Expand Down
47 changes: 44 additions & 3 deletions src/com/android/providers/media/scan/ModernMediaScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.Environment;
import android.os.FileUtils;
import android.os.OperationCanceledException;
import android.os.RemoteException;
import android.os.Trace;
import android.provider.MediaStore;
Expand All @@ -68,6 +70,7 @@
import android.util.Log;
import android.util.LongArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.providers.media.util.XmpInterface;

Expand Down Expand Up @@ -111,8 +114,6 @@ public class ModernMediaScanner implements MediaScanner {

// TODO: deprecate playlist editing
// TODO: deprecate PARENT column, since callers can't see directories
// TODO: replace PRIMARY/SECONDARY_DIRECTORY with PATH
// TODO: get real size column wired up for openable columns

private static final SimpleDateFormat sDateFormat;

Expand All @@ -131,6 +132,13 @@ public class ModernMediaScanner implements MediaScanner {
private final Context mContext;
private final ContentResolver mResolver;

/**
* Map from volume name to signals that can be used to cancel any active
* scan operations on those volumes.
*/
@GuardedBy("mSignals")
private final ArrayMap<String, CancellationSignal> mSignals = new ArrayMap<>();

public ModernMediaScanner(Context context) {
mContext = context;
mResolver = context.getContentResolver();
Expand All @@ -145,6 +153,7 @@ public Context getContext() {
public void scanDirectory(File file) {
try (Scan scan = new Scan(file)) {
scan.run();
} catch (OperationCanceledException ignored) {
}
}

Expand All @@ -153,6 +162,29 @@ public Uri scanFile(File file) {
try (Scan scan = new Scan(file)) {
scan.run();
return scan.mFirstResult;
} catch (OperationCanceledException ignored) {
return null;
}
}

@Override
public void onDetachVolume(String volumeName) {
synchronized (mSignals) {
final CancellationSignal signal = mSignals.remove(volumeName);
if (signal != null) {
signal.cancel();
}
}
}

private CancellationSignal getOrCreateSignal(String volumeName) {
synchronized (mSignals) {
CancellationSignal signal = mSignals.get(volumeName);
if (signal == null) {
signal = new CancellationSignal();
mSignals.put(volumeName, signal);
}
return signal;
}
}

Expand All @@ -165,6 +197,7 @@ private class Scan implements Runnable, FileVisitor<Path>, AutoCloseable {
private final File mRoot;
private final String mVolumeName;
private final Uri mFilesUri;
private final CancellationSignal mSignal;

private final ArrayList<ContentProviderOperation> mPending = new ArrayList<>();
private LongArray mScannedIds = new LongArray();
Expand All @@ -176,6 +209,7 @@ public Scan(File root) {
mRoot = root;
mVolumeName = MediaStore.getVolumeName(root);
mFilesUri = MediaStore.setIncludePending(MediaStore.Files.getContentUri(mVolumeName));
mSignal = getOrCreateSignal(mVolumeName);
}

@Override
Expand All @@ -198,13 +232,15 @@ public void run() {
final long[] scannedIds = mScannedIds.toArray();
Arrays.sort(scannedIds);

mSignal.throwIfCanceled();

// Second, clean up any deleted or hidden files, which are all items
// under requested location that weren't scanned above
Trace.traceBegin(Trace.TRACE_TAG_DATABASE, "clean");
try (Cursor c = mResolver.query(mFilesUri,
new String[] { FileColumns._ID }, FileColumns.DATA + " LIKE ? ESCAPE '\\'",
new String[] { escapeForLike(mRoot.getAbsolutePath()) + '%' },
FileColumns._ID + " DESC")) {
FileColumns._ID + " DESC", mSignal)) {
while (c.moveToNext()) {
final long id = c.getLong(0);
if (Arrays.binarySearch(scannedIds, id) < 0) {
Expand All @@ -221,6 +257,8 @@ public void run() {
Trace.traceEnd(Trace.TRACE_TAG_DATABASE);
}

mSignal.throwIfCanceled();

// Third, resolve any playlists that we scanned
for (int i = 0; i < mPlaylistIds.size(); i++) {
final Uri uri = MediaStore.Files.getContentUri(mVolumeName, mPlaylistIds.get(i));
Expand All @@ -245,6 +283,9 @@ public void close() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
// Possibly bail before digging into each directory
mSignal.throwIfCanceled();

if (isDirectoryHidden(dir.toFile())) {
return FileVisitResult.SKIP_SUBTREE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
import android.provider.MediaStore.Files.FileColumns;
import android.provider.MediaStore.MediaColumns;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.os.BackgroundThread;
import com.android.providers.media.MediaProvider;
import com.android.providers.media.scan.MediaScannerTest.IsolatedContext;
Expand All @@ -55,9 +58,6 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

@RunWith(AndroidJUnit4.class)
public class ModernMediaScannerTest {
// TODO: scan directory-vs-files and confirm identical results
Expand Down

0 comments on commit 68b2f06

Please sign in to comment.