frameworks/av/media/libmedia/MediaScanner.cpp
MediaScanResult MediaScanner::processDirectory(
const char *path, MediaScannerClient &client) {
int pathLength = strlen(path);
if (pathLength >= PATH_MAX) {
return MEDIA_SCAN_RESULT_SKIPPED;
}
char* pathBuffer = (char *)malloc(PATH_MAX + 1);
int pathRemaining = PATH_MAX - pathLength;
strcpy(pathBuffer, path);
if (pathLength > 0 && pathBuffer[pathLength - 1] != '/') {
pathBuffer[pathLength] = '/';
pathBuffer[pathLength + 1] = 0;
--pathRemaining;
}
client.setLocale(locale());
MediaScanResult result = doProcessDirectory(pathBuffer, pathRemaining, client, false);
return result;
}
MediaScanResult MediaScanner::doProcessDirectory(
char *path, int pathRemaining, MediaScannerClient &client, bool noMedia) {
// place to copy file or directory name
char* fileSpot = path + strlen(path);
struct dirent* entry;
if (shouldSkipDirectory(path)) {
ALOGD("Skipping: %s", path);
return MEDIA_SCAN_RESULT_OK;
}
// Treat all files as non-media in directories that contain a ".nomedia" file
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
strcpy(fileSpot, ".nomedia");
if (access(path, F_OK) == 0) {
ALOGV("found .nomedia, setting noMedia flag");
noMedia = true;
}
// restore path
fileSpot[0] = 0;
}
DIR* dir = opendir(path);
if (!dir) {
ALOGW("Error opening directory '%s', skipping: %s.", path, strerror(errno));
return MEDIA_SCAN_RESULT_SKIPPED;
}
MediaScanResult result = MEDIA_SCAN_RESULT_OK;
while ((entry = readdir(dir))) {
if (doProcessDirectoryEntry(path, pathRemaining, client, noMedia, entry, fileSpot)
== MEDIA_SCAN_RESULT_ERROR) {
result = MEDIA_SCAN_RESULT_ERROR;
break;
}
}
closedir(dir);
return result;
}
MediaScanResult MediaScanner::doProcessDirectoryEntry(
char *path, int pathRemaining, MediaScannerClient &client, bool noMedia,
struct dirent* entry, char* fileSpot) {
struct stat statbuf;
const char* name = entry->d_name;
// ignore "." and ".."
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
return MEDIA_SCAN_RESULT_SKIPPED;
}
int nameLength = strlen(name);
if (nameLength + 1 > pathRemaining) {
// path too long!
return MEDIA_SCAN_RESULT_SKIPPED;
}
strcpy(fileSpot, name);
int type = entry->d_type;
if (type == DT_UNKNOWN) {
// If the type is unknown, stat() the file instead.
// This is sometimes necessary when accessing NFS mounted filesystems, but
// could be needed in other cases well.
if (stat(path, &statbuf) == 0) {
if (S_ISREG(statbuf.st_mode)) {
type = DT_REG;
} else if (S_ISDIR(statbuf.st_mode)) {
type = DT_DIR;
}
} else {
ALOGD("stat() failed for %s: %s", path, strerror(errno) );
}
}
if (type == DT_DIR) {
bool childNoMedia = noMedia;
// set noMedia flag on directories with a name that starts with '.'
// for example, the Mac ".Trashes" directory
if (name[0] == '.')
childNoMedia = true;
// report the directory to the client
if (stat(path, &statbuf) == 0) {
status_t status = client.scanFile(path, statbuf.st_mtime, 0,
true /*isDirectory*/, childNoMedia);
if (status) {
return MEDIA_SCAN_RESULT_ERROR;
}
}
// and now process its contents
strcat(fileSpot, "/");
MediaScanResult result = doProcessDirectory(path, pathRemaining - nameLength - 1,
client, childNoMedia);
if (result == MEDIA_SCAN_RESULT_ERROR) {
return MEDIA_SCAN_RESULT_ERROR;
}
} else if (type == DT_REG) {
stat(path, &statbuf);
status_t status = client.scanFile(path, statbuf.st_mtime, statbuf.st_size,
false /*isDirectory*/, noMedia);
if (status) {
return MEDIA_SCAN_RESULT_ERROR;
}
}
return MEDIA_SCAN_RESULT_OK;
}
这里首先要解释下这些参数,path - 要扫描文件夹路径以’/’结尾,pathRemaining为路径长度与路径最大长度之间的差值,也就是防止扫描时路径超出范围,extensions 前面已经解释过是后缀,client是MyMediaScannerClient对象,后面两个参数是一些异常处理不用关心。大家仔细看这个函数的代码就可以知道,它完成的是遍历文件夹并找到有相应extensions 里面后缀的文件fileMatchesExtension(path, extensions),如果文件大小大于0就调用client.scanFile(path, statbuf.st_mtime, statbuf.st_size);来进行文件读取扫描 注意这里才会读文件的实际内容。
frameworks/base/media/jni/android_media_MediaScanner.cpp
MyMediaScannerClient : public MediaScannerClient
virtual status_t scanFile(const char* path, long long lastModified,
long long fileSize, bool isDirectory, bool noMedia)
{
jstring pathStr;
if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
mEnv->ExceptionClear();
return NO_MEMORY;
}
mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
fileSize, isDirectory, noMedia);
mEnv->DeleteLocalRef(pathStr);
return checkAndClearExceptionFromCallback(mEnv, "scanFile");
}
frameworks/base/media/java/android/media/MediaScanner.java
MyMediaScannerClient implements MediaScannerClient