`
guyikun
  • 浏览: 15571 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

MeidaProvider 流程学习笔记

阅读更多

参考代码:

./packages/providers/MediaProvider/src/com/android/providers/media/

MediaProvider.java

MediaScannerReceiver.java

MediaScannerService.java

MediaUpgradeReceiver.java

MtpReceiver.java

MtpService.java


./frameworks/base/media/java/android/media/

MediaScanner.java

./frameworks/base/media/java/android/mtp/

MtpDatabase.java

MtpServer.java

MtpStorage.java

MtpStorageInfo.java

./frameworks/base/media/jni/

android_media_MediaScanner.cpp

android_mtp_MtpDatabase.cpp

android_mtp_MtpServer.cpp

./frameworks/av/media/mtp/

MtpServer.h

MtpServer.cpp


MediaProvider主要用于创建媒体库的数据库表。对它的流程理解主要分为MTP流程、MediaScanner流程以及MediaProvider本身流程。

关于MeidaScanner和MediaProvider网上有较多的解释,这里主要说一下MTP的流程。


MTP流程

MediaProvider通过MtpReceiver(MtpReceiver.java::onReceive,31~42)建立了对于Usb接口的关联,一旦接收到usbState状态变化,则调用handleUsbState函数(MtpReceiver::handleUsbState,44~65),一旦发现UsbState是MTP(Media Transfer Protocal)或者是PTP(Picture Transfer Protocal)时就会启动MtpService服务(MtpService.java)。在MTPService中又建立了对于StorageEvent的监听,一旦Storage有Event发生,MtpServer(MtpServer.java)和MtpDatabase(MtpDataBase.java)函数就会被响应,具体看函数代码(MtpService.java::addStorageLocked 254~266)

private void addStorageLocked(StorageVolume volume) {

...

if (mDatabase != null) {

//MtpDatabase添加存储数据信息 1

mDatabase.addStorage(storage);

}

if (mServer != null) {

//mServer添加存储数据信息 2

mServer.addStorage(storage);

}

}

1 中只是建立了一个关于数据路径到数据的Map映射,关键还是看2

在2中唤起了一个native 函数android_mtp_MtpServer_add_storage,并由该函数调用MtpServer.cpp中的addStorage方法(android_mtp_MtpServer.cpp::120~150)

static void

android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)

{

...

server->addStorage(storage);

...

}

通过该方法由sendStoreAdded(storage->getStorageID()); //MtpServer.cpp::addStorage ,121行

发出一个MTP_EVENT_STORE_ADDED事件(MtpServer.cpp:: sendStoreAdded ,255~258行)

void MtpServer::sendStoreAdded(MtpStorageID id) {

ALOGV("sendStoreAdded %08X\n", id);

sendEvent(MTP_EVENT_STORE_ADDED, id);

}

由MtpServer的run接收到该Event后通过handleRequest函数分发执行该事 件响应(MtpServer.java:: run 153~228) 。

void MtpServer::run() {

...

if (handleRequest()) {...}

...

}

触发doSendObjectInfo(MtpResponseCode MtpServer::doSendObjectInfo 818~923),在该函数中MtpDatabase.beginSendObject函数被调用。

MtpResponseCode MtpServer::doSendObjectInfo() {

...

MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, format, parent, storageID, mSendObjectFileSize, modifiedTime);
...

}

从而在 doSendObjectInfo中MediaProvider插入该数据信息(MtpDatabase.java::doSendObjectInfo 206~304行)

private int beginSendObject(String path, int format, int parent,

int storageId, long size, long modified) {

...

Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);

...

}

同样,在MtpService.java中还有一个removeStorage 事件(MtpService.java::removeStorage 268~282)

private void removeStorageLocked(StorageVolume volume) {

...

if (mDatabase != null) {

mDatabase.removeStorage(storage);

}

if (mServer != null) {

mServer.removeStorage(storage);

}

}

由该函数唤起了native的android_mtp_MtpServer_remove_storage方法(android_mtp_MtpServer.cpp, 152~166)

static void

android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)

{

...

server->removeStorage(storage);

...

}

,过渡到MtpServer.cpp中的removeStorage函数(124~134)

void MtpServer::removeStorage(MtpStorage* storage) {

Mutex::Autolock autoLock(mMutex);

...

sendStoreRemoved(storage->getStorageID());

...

}

,并通过sendStoreRemoved函数触发MTP_EVENT_STORE_REMOVED事件,并由run函数接收到该事件后handleRequest到doSendObject函数中,并在该函 数最后调用mDatabase->endSendObjec去通知MediaScanner,canMtpFile。

MtpServer.cpp 915~986

MtpResponseCode MtpServer::doSendObject() {

...

done:

// reset so we don't attempt to send the data back

mData.reset();

mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat, result == MTP_RESPONSE_OK);

...

}

MtpDatabase.java 306~340

private void endSendObject(String path, int handle, int format, boolean succeeded) {

...

mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);

...

}

可参考:http://blog.csdn.net/innost/article/details/8876392


MediaScanner流程

这块的内容太多了,我就不具体介绍,需要的请参考

http://wenku.baidu.com/view/9151d3d349649b6648d747d2.html



深入理解Android 卷1 第10章

这里紧接着上面的函数,当MtpDatabase:: endSendObject执行了mMediaScanner.scanMtpFile函数后,便会由scanMtpFile函数通过MediaFile的类型判断,通知是否去执行MediaProvider的update操作。

MediaScanner.java 1477~1530行

public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {



if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) && !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType)) {

...

mMediaProvider.update(Files.getMtpObjectsUri(volumeName), values, "_id=?", whereArgs);

...

}

注:深入理解Android 卷1 第10章 图10-2MediaScanner扫描流程图将该过程归 纳的很详细,建议看一下。

与这个动作保持平行的是开机启动时,会由系统调用MediaScanner执行一次scanFile操作(MeidaScanner.java::scanFile 531~536行),并通过doScanFile函数中的endFile方法去判定是应该执行MediaProvider的update还是insert操作。


MediaProvider 流程

关于MediaProvider,虽然代码较多,但是主要还是对于媒体数据库的操作以及通知MediaScanner扫描文件信息。

具体可参考http://blog.csdn.net/evilcode/article/details/6321803

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics