Android Media Scanner Mechanism Analyze

转载自:http://blog.csdn.net/qikaibinglan/article/details/6126449

Architecture

 

 

pic1

 

 

Figure 2-1

As Figure 2-1. MediaScannerReciver start up at anytime where receive intent ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED or ACTION_MEDIA_SCANNER_SCAN_FILE. Cause on that spend long time to process the media metadata, so that MediaScannerReceiver will call up MediaScannerService.

MediaScannerService invoke a public class which named MediaScanner to do the scan work, MediaScanner handle the media database with a public class which named MediaProvider

MediaScannerReciver support two types of the folder:

1.internal volume, point to $(ANDROID_ROOT)/media.

2.External volume, point $(EXTERNAL_STORAGE).
Scanner Action


ACTION_BOOT_COMPLETED
public static final String ACTION_BOOT_COMPLETED

Broadcast Action: This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold theRECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.

This is a protected intent that can only be sent by the system.

Constant Value: "android.intent.action.BOOT_COMPLETED"
ACTION_MEDIA_MOUNTED
public static final String ACTION_MEDIA_MOUNTED

Broadcast Action: External media is present and mounted at its mount point. The path to the mount point for the removed media is contained in the Intent.mData field. The Intent contains an extra with name "read-only" and Boolean value to indicate if the media was mounted read only.

Constant Value: "android.intent.action.MEDIA_MOUNTED"
ACTION_MEDIA_SCANNER_SCAN_FILE.
public static final String ACTION_MEDIA_SCANNER_SCAN_FILE

Broadcast Action: Request the media scanner to scan a file and add it to the media database. The path to the file is contained in the Intent.mData field.

Constant Value: "android.intent.action.MEDIA_SCANNER_SCAN_FILE"
Android Media Scanner Receiver


We can find the source file with path anydroid/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java

public class MediaScannerReceiver extends BroadcastReceiver

{


@Override

public void onReceive(Context context, Intent intent) {

......

if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {

// scan internal storage

scan(context, MediaProvider.INTERNAL_VOLUME);

} else {

if (uri.getScheme().equals("file")) {

// handle intents related to external storage

String path = uri.getPath();

if (action.equals(Intent.ACTION_MEDIA_MOUNTED) &&

externalStoragePath.equals(path)) {

scan(context, MediaProvider.EXTERNAL_VOLUME);

} else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) &&

path != null && path.startsWith(externalStoragePath + "/")) {

scanFile(context, path);

}

}

}

}


private void scan(Context context, String volume) {

Bundle args = new Bundle();

args.putString("volume", volume);

context.startService(

new Intent(context, MediaScannerService.class).putExtras(args));

}


private void scanFile(Context context, String path) {

Bundle args = new Bundle();

args.putString("filepath", path);

context.startService(

new Intent(context, MediaScannerService.class).putExtras(args));

}

}

pic2


Figure 4-1

As the source codes, and Figure 4-1, there are two different media database in the system, one is the internal storage , the other is the external storage. Finally, they call the method startService() to start the MediaScannerService.
Android Media Scanner Service

We can find the source file with path /android/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerService.java .

public void onCreate()

{

......

Thread thr = new Thread(null, this, "MediaScannerService");

thr.start();

}

public int onStartCommand(Intent intent, int flags, int startId)

{

......

Message msg = mServiceHandler.obtainMessage();

......

mServiceHandler.sendMessage(msg); return Service.START_REDELIVER_INTENT;

}

public void run()

{

......

mServiceHandler = new ServiceHandler();

......

}

private final class ServiceHandler extends Handler

{

......

@Override

public void handleMessage(Message msg)

{

......

if (filePath != null) {

......

Uri uri = scanFile(filePath, arguments.getString("mimetype"));

......

}

else {

......

scan(directories, volume);

......

}

}

}

private void scan(String[] directories, String volumeName) {

......

MediaScanner scanner = createMediaScanner();

scanner.scanDirectories(directories, volumeName);

......

}

private Uri scanFile(String path, String mimeType) {

......

MediaScanner scanner = createMediaScanner();

return scanner.scanSingleFile(path, volumeName, mimeType);

}

pic3


Figure 5-1



Android application maybe block with invoking service, generic create a thread to run at the backend. First, media service call onCreate() to start the service if it is not exist, then create a thread and run thread.start() to call the runnable method which has implemented with the run(). In the run(), invoke a internal class named ServiceHandler to scan file. In the method scan() and scanFile(), they all invoke a public class named MediaScanner whom has method named createMediaScanner() to process metadata and media dabase.
Android Media Scanner

We can find the relate files with path android/frameworks/base/media/java/android/media,

pic4
Figure 6-1



java codes

file://android/frameworks/base/media/java/android/media/MediaScanner.java

public void scanDirectories(String[] directories, String volumeName) {

......


for (int i = 0; i < directories.length; i++) {

processDirectory(directories[i], MediaFile.sFileExtensions, mClient);

}

......

}

}



public void scanFile(String path, long lastModified, long fileSize) {

// This is the callback funtion from native codes.

// Log.v(TAG, "scanFile: "+path);

doScanFile(path, null, lastModified, fileSize, false);

}


public void scanFile(String path, String mimeType, long lastModified, long fileSize) {

doScanFile(path, mimeType, lastModified, fileSize, false);

}



public Uri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) {

......

if( isMetadataSupported(mFileType) ) {

processFile(path, mimeType, this);

} else if (MediaFile.isImageFileType(mFileType)) {

// we used to compute the width and height but it's not worth it

}


result = endFile(entry, ringtones, notifications, alarms, music, podcasts);

......

}



private Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications,

boolean alarms, boolean music, boolean podcasts)

throws RemoteException {



......

mMediaProvider.insert(...) // mMediaProvider.update(...)

......

}



private native void processDirectory(String path, String extensions, MediaScannerClient client);

private native void processFile(String path, String mimeType, MediaScannerClient client);







c++ codes

file://android/frameworks/base/media/jni/android_media_MediaScanner.cpp

static void

android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jstring extensions, jobject client)

{

MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);


......


MyMediaScannerClient myClient(env, client);

mp->processDirectory(pathStr, extensionsStr, myClient, ExceptionCheck, env);

......

}



static void

android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client)

{

MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); ......

MyMediaScannerClient myClient(env, client);

mp->processFile(pathStr, mimeTypeStr, myClient);

......

}



file://android/external/opencore/android/mediascanner.cpp

status_t MediaScanner::processDirectory(const char *path, const char* extensions,

MediaScannerClient& client, ExceptionCheck exceptionCheck, void* exceptionEnv)

{

......

result = doProcessDirectory(pathBuffer, pathRemaining, extensions, client, exceptionCheck, exceptionEnv);

......

}



status_t MediaScanner::doProcessDirectory(char *path, int pathRemaining, const char* extensions,

MediaScannerClient& client, ExceptionCheck exceptionCheck, void* exceptionEnv)

{

......

client.scanFile(path, statbuf.st_mtime, statbuf.st_size);

......

}



status_t MediaScanner::processFile(const char *path, const char* mimeType, MediaScannerClient& client)

{

status_t result = PVMFSuccess;

int error = 0;

InitializeForThread();


OSCL_TRY(error,

client.setLocale(mLocale);

client.beginFile();


//LOGD("processFile %s mimeType: %s/n", path, mimeType);

const char* extension = strrchr(path, '.');


if (extension &&

(strcasecmp(extension, ".mp3") == 0 || strcasecmp(extension, ".aac") == 0)) {

// Both mp3 and aac files use ID3 tags to hold metadata

result = parseID3Tag(path, client);

} else if (extension &&

(strcasecmp(extension, ".mp4") == 0 || strcasecmp(extension, ".m4a") == 0 ||

strcasecmp(extension, ".3gp") == 0 || strcasecmp(extension, ".3gpp") == 0 ||

strcasecmp(extension, ".3g2") == 0 || strcasecmp(extension, ".m4b") == 0 ||

strcasecmp(extension, ".3gpp2") == 0)) {

result = parseMP4(path, client);

} else if (extension && strcasecmp(extension, ".ogg") == 0) {

result = parseOgg(path, client);

} else if (extension &&

(strcasecmp(extension, ".mid") == 0 || strcasecmp(extension, ".smf") == 0 ||

strcasecmp(extension, ".imy") == 0)) {

result = parseMidi(path, client);

} else if (extension &&

(strcasecmp(extension, ".wma") == 0 || strcasecmp(extension, ".wmv") == 0 ||

strcasecmp(extension, ".asf") == 0 || strcasecmp(extension, ".amr") == 0 ||

strcasecmp(extension, ".wav") == 0 || strcasecmp(extension, ".awb") == 0)) {

result = parseASF(path, client);

} else {

result = PVMFFailure;

}

client.endFile();

);


OSCL_FIRST_CATCH_ANY( error,LOGV("OSCL_LEAVE happened in processFile Exit with failure");return PVMFFailure);

return result;

}





As Figure 6-1, If scanDirectory() has called by MediaScannerService, it will invoke c++ llibrary libmedia_jni method processDiretorys() by JNI mechanism, then processDiretorys() invoke JAVA class MyMediaScannerClient by JNI, Finaly, endFile() use to insert or update the database.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园失物招领系统管理系统按照操作主体分为管理员和用户。管理员的功能包括字典管理、论坛管理、公告信息管理、失物招领管理、失物认领管理、寻物启示管理、寻物认领管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 校园失物招领系统管理系统可以提高校园失物招领系统信息管理问题的解决效率,优化校园失物招领系统信息处理流程,保证校园失物招领系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 ,管理员权限操作的功能包括管理公告,管理校园失物招领系统信息,包括失物招领管理,培训管理,寻物启事管理,薪资管理等,可以管理公告。 失物招领管理界面,管理员在失物招领管理界面中可以对界面中显示,可以对失物招领信息的失物招领状态进行查看,可以添加新的失物招领信息等。寻物启事管理界面,管理员在寻物启事管理界面中查看寻物启事种类信息,寻物启事描述信息,新增寻物启事信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值