Skip to content

Commit c164faa

Browse files
committed
Speed up playlist processing
The recent removal of the cache from MediaScanner (commit 58ef689) slowed down processing of playlists, in some cases significantly, due to every line in a playlist prompting a query that looped over the entire audio table. With this change, the query is only done once instead of for every line, and the code starts iterating over the Cursor starting near the point of the last match, instead of from the start. The latter is especially helpful when the entire query result is too large to fit in a CursorWindow, since it reduces the number of times that sqlite has to perform an offset query under the hood to refil the window. Change-Id: I9fea990b3b8c86571384de2122708fb7e809c355
1 parent da9deca commit c164faa

File tree

1 file changed

+58
-34
lines changed

1 file changed

+58
-34
lines changed

media/java/android/media/MediaScanner.java

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,14 +1396,17 @@ public void scanMtpFile(String path, String volumeName, int objectHandle, int fo
13961396
}
13971397

13981398
mMtpObjectHandle = objectHandle;
1399+
Cursor fileList = null;
13991400
try {
14001401
if (MediaFile.isPlayListFileType(fileType)) {
14011402
// build file cache so we can look up tracks in the playlist
14021403
prescan(null, true);
14031404

14041405
FileEntry entry = makeEntryFor(path);
14051406
if (entry != null) {
1406-
processPlayList(entry);
1407+
fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
1408+
null, null, null, null);
1409+
processPlayList(entry, fileList);
14071410
}
14081411
} else {
14091412
// MTP will create a file entry for us so we don't want to do it in prescan
@@ -1417,6 +1420,9 @@ public void scanMtpFile(String path, String volumeName, int objectHandle, int fo
14171420
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
14181421
} finally {
14191422
mMtpObjectHandle = 0;
1423+
if (fileList != null) {
1424+
fileList.close();
1425+
}
14201426
}
14211427
}
14221428

@@ -1479,7 +1485,7 @@ private int matchPaths(String path1, String path2) {
14791485
}
14801486

14811487
private boolean addPlayListEntry(String entry, String playListDirectory,
1482-
Uri uri, ContentValues values, int index) {
1488+
Uri uri, ContentValues values, int index, Cursor fileList) {
14831489

14841490
// watch for trailing whitespace
14851491
int entryLength = entry.length();
@@ -1506,19 +1512,20 @@ private boolean addPlayListEntry(String entry, String playListDirectory,
15061512
// number of rightmost file/directory names for bestMatch
15071513
int bestMatchLength = 0;
15081514

1509-
Cursor c = null;
1510-
try {
1511-
c = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
1512-
null, null, null, null);
1513-
} catch (RemoteException e1) {
1514-
}
1515-
1516-
if (c != null) {
1517-
while (c.moveToNext()) {
1518-
long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
1519-
String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
1520-
int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
1521-
long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
1515+
if (fileList != null) {
1516+
int count = fileList.getCount();
1517+
// Backing up a little in the cursor helps when the files in the
1518+
// playlist are not in the same order as they are in the database
1519+
// but are still close.
1520+
fileList.move(-1000);
1521+
while(--count >= 0) {
1522+
if (!fileList.moveToNext()) {
1523+
fileList.moveToFirst();
1524+
}
1525+
long rowId = fileList.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
1526+
String path = fileList.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
1527+
int format = fileList.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
1528+
long lastModified = fileList.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
15221529

15231530
if (path.equalsIgnoreCase(entry)) {
15241531
bestMatch = new FileEntry(rowId, path, lastModified, format);
@@ -1531,7 +1538,6 @@ private boolean addPlayListEntry(String entry, String playListDirectory,
15311538
bestMatchLength = matchLength;
15321539
}
15331540
}
1534-
c.close();
15351541
}
15361542

15371543
if (bestMatch == null) {
@@ -1541,7 +1547,7 @@ private boolean addPlayListEntry(String entry, String playListDirectory,
15411547
try {
15421548
// check rowid is set. Rowid may be missing if it is inserted by bulkInsert().
15431549
if (bestMatch.mRowId == 0) {
1544-
c = mMediaProvider.query(mAudioUri, ID_PROJECTION,
1550+
Cursor c = mMediaProvider.query(mAudioUri, ID_PROJECTION,
15451551
MediaStore.Files.FileColumns.DATA + "=?",
15461552
new String[] { bestMatch.mPath }, null, null);
15471553
if (c != null) {
@@ -1567,7 +1573,8 @@ private boolean addPlayListEntry(String entry, String playListDirectory,
15671573
return true;
15681574
}
15691575

1570-
private void processM3uPlayList(String path, String playListDirectory, Uri uri, ContentValues values) {
1576+
private void processM3uPlayList(String path, String playListDirectory, Uri uri,
1577+
ContentValues values, Cursor fileList) {
15711578
BufferedReader reader = null;
15721579
try {
15731580
File f = new File(path);
@@ -1580,7 +1587,7 @@ private void processM3uPlayList(String path, String playListDirectory, Uri uri,
15801587
// ignore comment lines, which begin with '#'
15811588
if (line.length() > 0 && line.charAt(0) != '#') {
15821589
values.clear();
1583-
if (addPlayListEntry(line, playListDirectory, uri, values, index))
1590+
if (addPlayListEntry(line, playListDirectory, uri, values, index, fileList))
15841591
index++;
15851592
}
15861593
line = reader.readLine();
@@ -1598,7 +1605,8 @@ private void processM3uPlayList(String path, String playListDirectory, Uri uri,
15981605
}
15991606
}
16001607

1601-
private void processPlsPlayList(String path, String playListDirectory, Uri uri, ContentValues values) {
1608+
private void processPlsPlayList(String path, String playListDirectory, Uri uri,
1609+
ContentValues values, Cursor fileList) {
16021610
BufferedReader reader = null;
16031611
try {
16041612
File f = new File(path);
@@ -1613,7 +1621,8 @@ private void processPlsPlayList(String path, String playListDirectory, Uri uri,
16131621
int equals = line.indexOf('=');
16141622
if (equals > 0) {
16151623
values.clear();
1616-
if (addPlayListEntry(line.substring(equals + 1), playListDirectory, uri, values, index))
1624+
if (addPlayListEntry(line.substring(equals + 1), playListDirectory,
1625+
uri, values, index, fileList))
16171626
index++;
16181627
}
16191628
}
@@ -1637,12 +1646,14 @@ class WplHandler implements ElementListener {
16371646
final ContentHandler handler;
16381647
String playListDirectory;
16391648
Uri uri;
1649+
Cursor fileList;
16401650
ContentValues values = new ContentValues();
16411651
int index = 0;
16421652

1643-
public WplHandler(String playListDirectory, Uri uri) {
1653+
public WplHandler(String playListDirectory, Uri uri, Cursor fileList) {
16441654
this.playListDirectory = playListDirectory;
16451655
this.uri = uri;
1656+
this.fileList = fileList;
16461657

16471658
RootElement root = new RootElement("smil");
16481659
Element body = root.getChild("body");
@@ -1653,11 +1664,12 @@ public WplHandler(String playListDirectory, Uri uri) {
16531664
this.handler = root.getContentHandler();
16541665
}
16551666

1667+
@Override
16561668
public void start(Attributes attributes) {
16571669
String path = attributes.getValue("", "src");
16581670
if (path != null) {
16591671
values.clear();
1660-
if (addPlayListEntry(path, playListDirectory, uri, values, index)) {
1672+
if (addPlayListEntry(path, playListDirectory, uri, values, index, fileList)) {
16611673
index++;
16621674
}
16631675
}
@@ -1671,14 +1683,16 @@ ContentHandler getContentHandler() {
16711683
}
16721684
}
16731685

1674-
private void processWplPlayList(String path, String playListDirectory, Uri uri) {
1686+
private void processWplPlayList(String path, String playListDirectory, Uri uri,
1687+
Cursor fileList) {
16751688
FileInputStream fis = null;
16761689
try {
16771690
File f = new File(path);
16781691
if (f.exists()) {
16791692
fis = new FileInputStream(f);
16801693

1681-
Xml.parse(fis, Xml.findEncodingByName("UTF-8"), new WplHandler(playListDirectory, uri).getContentHandler());
1694+
Xml.parse(fis, Xml.findEncodingByName("UTF-8"),
1695+
new WplHandler(playListDirectory, uri, fileList).getContentHandler());
16821696
}
16831697
} catch (SAXException e) {
16841698
e.printStackTrace();
@@ -1694,7 +1708,7 @@ private void processWplPlayList(String path, String playListDirectory, Uri uri)
16941708
}
16951709
}
16961710

1697-
private void processPlayList(FileEntry entry) throws RemoteException {
1711+
private void processPlayList(FileEntry entry, Cursor fileList) throws RemoteException {
16981712
String path = entry.mPath;
16991713
ContentValues values = new ContentValues();
17001714
int lastSlash = path.lastIndexOf('/');
@@ -1736,21 +1750,31 @@ private void processPlayList(FileEntry entry) throws RemoteException {
17361750
int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
17371751

17381752
if (fileType == MediaFile.FILE_TYPE_M3U) {
1739-
processM3uPlayList(path, playListDirectory, membersUri, values);
1753+
processM3uPlayList(path, playListDirectory, membersUri, values, fileList);
17401754
} else if (fileType == MediaFile.FILE_TYPE_PLS) {
1741-
processPlsPlayList(path, playListDirectory, membersUri, values);
1755+
processPlsPlayList(path, playListDirectory, membersUri, values, fileList);
17421756
} else if (fileType == MediaFile.FILE_TYPE_WPL) {
1743-
processWplPlayList(path, playListDirectory, membersUri);
1757+
processWplPlayList(path, playListDirectory, membersUri, fileList);
17441758
}
17451759
}
17461760

17471761
private void processPlayLists() throws RemoteException {
17481762
Iterator<FileEntry> iterator = mPlayLists.iterator();
1749-
while (iterator.hasNext()) {
1750-
FileEntry entry = iterator.next();
1751-
// only process playlist files if they are new or have been modified since the last scan
1752-
if (entry.mLastModifiedChanged) {
1753-
processPlayList(entry);
1763+
Cursor fileList = null;
1764+
try {
1765+
fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
1766+
null, null, null, null);
1767+
while (iterator.hasNext()) {
1768+
FileEntry entry = iterator.next();
1769+
// only process playlist files if they are new or have been modified since the last scan
1770+
if (entry.mLastModifiedChanged) {
1771+
processPlayList(entry, fileList);
1772+
}
1773+
}
1774+
} catch (RemoteException e1) {
1775+
} finally {
1776+
if (fileList != null) {
1777+
fileList.close();
17541778
}
17551779
}
17561780
}

0 commit comments

Comments
 (0)