Android Media Scanner Mechanism Analyze

 

Architecture

media scanner schema

Figure2-1

 

AsFigure 2-1. MediaScannerReciver start up at anytime where receiveintent ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED orACTION_MEDIA_SCANNER_SCAN_FILE. Cause on that spend long time to process the media metadata, so that MediaScannerReceiver will call upMediaScannerService.

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

MediaScannerReciversupport two types of the folder:

    1.internalvolume, point to $(ANDROID_ROOT)/media.

    2.Externalvolume, point $(EXTERNAL_STORAGE).

ScannerAction

ACTION_BOOT_COMPLETED

publicstatic final String ACTION_BOOT_COMPLETED

BroadcastAction: This is broadcast once, afterthe system has finished booting. It can be used to performapplication-specific initialization, such as installing alarms. Youmust hold theRECEIVE_BOOT_COMPLETED permissionin order to receive this broadcast.

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

ConstantValue: "android.intent.action.BOOT_COMPLETED"

 

ACTION_MEDIA_MOUNTED

publicstatic final String ACTION_MEDIA_MOUNTED

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

ConstantValue: "android.intent.action.MEDIA_MOUNTED"

 

ACTION_MEDIA_SCANNER_SCAN_FILE.

publicstatic final String ACTION_MEDIA_SCANNER_SCAN_FILE

BroadcastAction: Request the media scanner to scan a file and add it to themedia database. The path to the file is contained in the Intent.mDatafield.

ConstantValue: "android.intent.action.MEDIA_SCANNER_SCAN_FILE"

 

 

AndroidMedia Scanner Receiver

Wecan find the source file with pathanydroid/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java

 

publicclass MediaScannerReceiver extends BroadcastReceiver

{

@Override

publicvoid 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

Stringpath = 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);

}

}

}

}

privatevoid scan(Context context, String volume) {

Bundleargs = new Bundle();

args.putString("volume",volume);

context.startService(

newIntent(context, MediaScannerService.class).putExtras(args));

}

privatevoid scanFile(Context context, String path) {

Bundleargs = new Bundle();

args.putString("filepath",path);

context.startService(

newIntent(context, MediaScannerService.class).putExtras(args));

}

}

scanner receiver

Figure4-1

Asthe source codes, and Figure 4-1, there are two different mediadatabase in the system, oneis the internal storage , the other is the external storage. Finally,they call the method startService() to start the MediaScannerService.

 

AndroidMedia Scanner Service

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

 

publicvoid onCreate()

{

......

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

thr.start();

}

 

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

{

......

Messagemsg = mServiceHandler.obtainMessage();

......

mServiceHandler.sendMessage(msg); returnService.START_REDELIVER_INTENT;

}

 

publicvoid run()

{

......

mServiceHandler= new ServiceHandler();

......

}

 

privatefinal class ServiceHandler extends Handler

{

......

@Override

publicvoid handleMessage(Message msg)

{

......

if(filePath != null) {

......

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

......

}

else{

......

scan(directories,volume);

......

}

}

}

 

privatevoid scan(String[] directories, String volumeName) {

......

MediaScannerscanner = createMediaScanner();

scanner.scanDirectories(directories,volumeName);

......

}

 

privateUri scanFile(String path, String mimeType) {

......

MediaScannerscanner = createMediaScanner();

returnscanner.scanSingleFile(path, volumeName, mimeType);

}

 

 

scanner service

Figure5-1

 

Androidapplication maybe block with invoking service, generic create a thread to run at the backend. First, media service call onCreate() tostart the service if it is not exist, then create a thread and runthread.start() to call the runnable method which has implemented withthe run(). In the run(), invoke a internal class named ServiceHandlerto scan file. In the method scan() and scanFile(), they all invoke apublic class named MediaScanner whom has method namedcreateMediaScanner() to process metadata and media dabase.

 

AndroidMedia Scanner

Wecan find the relate files with pathandroid/frameworks/base/media/java/android/media,

 

media scanner

 

Figure6-1

 

javacodes

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

publicvoid scanDirectories(String[] directories, String volumeName) {

......

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

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

}

......

}

}

 

publicvoid 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);

}

publicvoid scanFile(String path, String mimeType, long lastModified, longfileSize) {

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

}

 

publicUri doScanFile(String path, String mimeType, long lastModified, longfileSize, 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);

......

}

 

privateUri endFile(FileCacheEntry entry, boolean ringtones, booleannotifications,

boolean alarms,boolean music, boolean podcasts)

throwsRemoteException {

 

......

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

......

}

 

privatenative void processDirectory(String path, String extensions,MediaScannerClient client);

privatenative void processFile(String path, String mimeType,MediaScannerClient client);

 

 

 

c++codes

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

staticvoid

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

{

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

......

MyMediaScannerClientmyClient(env, client);

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

......

}

 

staticvoid

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

{

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

MyMediaScannerClientmyClient(env, client);

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

......

}

 

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

status_tMediaScanner::processDirectory(const char *path, const char*extensions,

MediaScannerClient&client, ExceptionCheck exceptionCheck, void* exceptionEnv)

{

......

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

......

}

 

status_tMediaScanner::doProcessDirectory(char *path, int pathRemaining, constchar* extensions,

MediaScannerClient&client, ExceptionCheck exceptionCheck, void* exceptionEnv)

{

......

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

......

}

 

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

{

status_t result =PVMFSuccess;

interror = 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 aacfiles 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 withfailure");return PVMFFailure);

return result;

}

 

 

AsFigure 6-1, If scanDirectory() has called by MediaScannerService, itwill invoke c++ llibrary libmedia_jni method processDiretorys() byJNI mechanism, then processDiretorys() invoke JAVA classMyMediaScannerClient by JNI, Finaly, endFile() use to insert orupdate the database.

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值