参考代码:
./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
./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