android Media process

本文详细介绍了Android系统中媒体文件的扫描与元数据解析过程。包括MediaScannerReceiver启动时机、扫描目录分类、文件类型支持、Java层与C++层的工作流程等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android Media Scanner Process
[First written by Steve Guo, please keep the mark if forwarding.]

Here is the overall picture.

android.process.media
MediaScannerReceiver is started when any ACTION_BOOT_COMPLETED, ACTION_MEDIA_MOUNTED or ACTION_MEDIA_SCANNER_SCAN_FILE intent is sent out. Because it may cost a lot of time to parse meta-data information of media files, MediaScannerReceiver will start MediaScannerService. MediaScannerService calls a utility class MediaScanner to do the real work. MediaScannerReceiver maintains two kinds of scan directories: One is internal volume which points to $(ANDROID_ROOT)/media. Another is external volume which points to $(EXTERNAL_STORAGE).

The scan and parse work lies in both JAVA and C++ layer. JAVA layer is the starter. To scan the whole directory, MediaScanner does the following steps.

1. JAVA layer initialize

In this step, it will open different database according to whether the dir is internal or external volume.

2. JAVA layer prescan

It first clears file and play list cache entries, then generates new file and play list cache entries according to query result from MediaProvider.

3. C++ layer processDirectory

It enumerates all files and sub-dirs in a specific dir(If a sub-dir contains a .nomedia hidden file, it won’t be enumerated.). For each enumerated file, it judges whether the file is supported according to file extension. If the file extension is supported, then C++ layer will call back to JAVA layer scanFile. The file extension which will be scanned is listed in MediaFile.java. Here is the list.

/* Audio */
addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg");
addFileType("M4A", FILE_TYPE_M4A, "audio/mp4");
addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav");
addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb");
addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
addFileType("XMF", FILE_TYPE_MID, "audio/midi");
addFileType("RTTTL", FILE_TYPE_MID, "audio/midi");
addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi");
addFileType("IMY", FILE_TYPE_IMY, "audio/imelody");


/* Video */

addFileType("MP4", FILE_TYPE_MP4, "video/mp4");
addFileType("M4V", FILE_TYPE_M4V, "video/mp4");
addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp");
addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp");
addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");


/* Image */

addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("GIF", FILE_TYPE_GIF, "image/gif");
addFileType("PNG", FILE_TYPE_PNG, "image/png");
addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp");
addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");


/* Audio Play List */

addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl");
addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls");
addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl");


4. JAVA layer scanFile

a) JAVA layer beginFile

First it ignores some special files for MacOS and Windows Media Player. Then it looks whether the file has been in the cache entry, if so, it will check whether the file’s last modification time is changed. Finally it returns the result whether the file needs to be processed further. If no need, the following two steps won’t be executed.

b) C++ layer scanFile

Not all the files will be delivered to let C++ layer parse meta-data. Only the following file types will be parsed. Pay attention here, image files are not handled here.

if (mFileType == MediaFile.FILE_TYPE_MP3 ||mFileType == MediaFile.FILE_TYPE_MP4 ||
mFileType == MediaFile.FILE_TYPE_M4A ||mFileType == MediaFile.FILE_TYPE_3GPP ||
mFileType == MediaFile.FILE_TYPE_3GPP2 ||mFileType == MediaFile.FILE_TYPE_OGG ||
mFileType == MediaFile.FILE_TYPE_MID ||mFileType == MediaFile.FILE_TYPE_WMA) {
......
}

 
For each parsed meta-data information, C++ layer will call back to JAVA layer handleStringTag. JAVA layer will record the name/value information.

c) JAVA layer endFile

Finally JAVA layer updates the corresponding database table provided by MeidaProvider according to the values parsed at the previous step.

5. JAVA layer postScan

Until now, all the files have been scanned, it finally checks the file and play list cache entry to see whether all items still existed in the file system. If have any empty entry, then delete it from database. So that it can keep some kinds of consistence between database and file system.

Other application can know when the scan operation starts and ends through receiving ACTION_MEDIA_SCANNER_STARTED and ACTION_MEDIA_SCANNER_FINISHED intents sent from MediaScannerService.

 

### 解决Android系统进程中的媒体处理崩溃问题 对于`android.process.media` 进程的崩溃,通常涉及到多媒体组件如 `MediaMetadataRetriever` 的使用不当。当遇到“`android.media.MediaMetadataRetriever.finalize()` timed out”的错误时,这表明存在资源未被正确释放的情况[^4]。 #### 使用全局异常处理器捕获未处理异常 为了更好地捕捉并分析导致崩溃的原因,在应用程序层面设置默认的未捕获异常处理器是一种有效的方法。通过调用 `Thread.setDefaultUncaughtExceptionHandler()` 可以为整个应用指定一个统一的异常处理逻辑,这种方法适用于所有的 Android 版本[^2]。 ```java public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, Throwable throwable) { // 自定义的日志记录或其他操作 // 继续传播给系统的默认处理器 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } }); } } ``` #### 正确管理 `MediaMetadataRetriever` 生命周期 针对具体的 `MediaMetadataRetriever` 导致的问题,应当确保每次使用完毕之后立即调用其 `release()` 方法来显式地释放关联的资源: ```java MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(filePathOrUrl); String durationStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); } finally { retriever.release(); // 确保总是执行 release() } ``` 此外,建议减少频繁创建和销毁此类对象的操作频率,尽可能重用已有的实例以降低内存压力。 #### 日志监控与调试 正常的日志输出可以帮助开发者了解程序运行状态以及潜在的风险点。例如下面这段来自系统服务的日志片段显示了一个权限验证的过程[^3]: ``` E qc_debug: checkedGrants = false callpid = 4672 callingUid = 10041 opening provider... ``` 定期查看这些日志有助于提前发现可能引发崩溃的因素,并采取预防措施加以规避。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值