Android Framework media providers 随笔
遇到一个问题是多媒体扫描失败:
11-24 09:50:54.424 3886 3886 E lowmemorykiller: Error writing /proc/4647/oom_score_adj; errno=22
11-24 09:50:54.430 4216 4227 E JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 76)
11-24 09:50:54.431 4216 4227 I ActivityManager: Process android.process.media (pid 4647) has died
从logcat 中可以看到的时候 这个服务com.android.providers.media/.MediaScannerService 启动超时了
Line 2012: 11-23 11:55:04.410 4216 4229 I ActivityManager: Force stopping com.android.providers.media appid=10006 user=-1: vold reset
Line 2309: 11-24 09:47:58.651 4216 4394 I BroadcastQueue: Delay finish: com.android.providers.media/.MediaScannerReceiver
Line 2338: 11-24 09:48:13.653 4216 4229 I ActivityManager: Waited long enough for: ServiceRecord{50712f4 u0 com.android.providers.media/.MediaScannerService}
Line 2450: 11-24 09:50:54.023 4647 4647 I chatty : uid=10006(com.android.providers.media) expire 1 line
Line 2457: 11-24 09:50:54.029 4647 5471 I chatty : uid=10006(com.android.providers.media) expire 13 lines
Line 2540: 11-24 09:50:54.431 4216 4227 I ActivityManager: Existing provider com.android.providers.media/.MediaProvider is crashing; detaching ProcessRecord{65cbd94 4694:com.xxx.xxx/1000}
Line 2543: 11-24 09:50:54.431 4216 4227 W ActivityManager: Scheduling restart of crashed service com.android.providers.media/.MediaScannerService in 351562ms
1、com.android.providers.media 和 com.android.providers.media/.MediaScannerService 到底是在哪里定义声明的?
2、Why com.android.providers.media/.MediaProvider is crashing?
带着问题扩展开来学习,遇到什么记录什么,慢慢搭建系统的体系
平台:Android 7.1
1、com.android.providers.media 与 MediaScannerService
看 frameworks\base\media\java\android\media\MediaScannerConnection.java 的构造方法和connect 方法, 其注释和接口实现可以回答之前的疑问
/**
* MediaScannerConnection provides a way for applications to pass a
* newly created or downloaded media file to the media scanner service.
* The media scanner service will read metadata from the file and add
* the file to the media content provider.
* The MediaScannerConnectionClient provides an interface for the
* media scanner service to return the Uri for a newly scanned file
* to the client of the MediaScannerConnection class.
*/
public class MediaScannerConnection implements ServiceConnection
如下接口通过
new ComponentName("com.android.providers.media",
"com.android.providers.media.MediaScannerService"));
/**
* Initiates a connection to the media scanner service.
* {@link MediaScannerConnectionClient#onMediaScannerConnected()}
* will be called when the connection is established.
*/
public void connect() {
synchronized (this) {
if (!mConnected) {
Intent intent = new Intent(IMediaScannerService.class.getName());
intent.setComponent(
new ComponentName("com.android.providers.media",
"com.android.providers.media.MediaScannerService"));
mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
mConnected = true;
}
}
}
而 MediaScannerService 我们只需要看如下文件中的注释就对其流程有一个清晰的了解
frameworks\base\media\java\android\media\MediaScanner.java
/**
* Internal service helper that no-one should use directly.
*
* The way the scan currently works is:
* - The Java MediaScannerService creates a MediaScanner (this class), and calls
* MediaScanner.scanDirectories on it.
* - scanDirectories() calls the native processDirectory() for each of the specified directories.
* - the processDirectory() JNI method wraps the provided mediascanner client in a native
* 'MyMediaScannerClient' class, then calls processDirectory() on the native MediaScanner
* object (which got created when the Java MediaScanner was created).
* - native MediaScanner.processDirectory() calls
* doProcessDirectory(), which recurses over the folder, and calls
* native MyMediaScannerClient.scanFile() for every file whose extension matches.
* - native MyMediaScannerClient.scanFile() calls back on Java MediaScannerClient.scanFile,
* which calls doScanFile, which after some setup calls back down to native code, calling
* MediaScanner.processFile().
* - MediaScanner.processFile() calls one of several methods, depending on the type of the
* file: parseMP3, parseMP4, parseMidi, parseOgg or parseWMA.
* - each of these methods gets metadata key/value pairs from the file, and repeatedly
* calls native MyMediaScannerClient.handleStringTag, which calls back up to its Java
* counterparts in this file.
* - Java handleStringTag() gathers the key/value pairs that it's interested in.
* - once processFile returns and we're back in Java code in doScanFile(), it calls
* Java MyMediaScannerClient.endFile(), which takes all the data that's been
* gathered and inserts an entry in to the database.
*
* In summary:
* Java MediaScannerService calls
* Java MediaScanner scanDirectories, which calls
* Java MediaScanner processDirectory (native method), which calls
* native MediaScanner processDirectory, which calls
* native MyMediaScannerClient scanFile, which calls
* Java MyMediaScannerClient scanFile, which calls
* Java MediaScannerClient doScanFile, which calls
* Java MediaScanner processFile (native method), which calls
* native MediaScanner processFile, which calls
* native parseMP3, parseMP4, parseMidi, parseOgg or parseWMA, which calls
* native MyMediaScanner handleStringTag, which calls
* Java MyMediaScanner handleStringTag.
* Once MediaScanner processFile returns, an entry is inserted in to the database.
*
* The MediaScanner class is not thread-safe, so it should only be used in a single threaded manner.
*
* {@hide}
*/
public class MediaScanner implements AutoCloseable
2、Why com.android.providers.media/.MediaProvider is crashing?
在
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java getContentProviderImpl函数中会对 OomAdj 优先级进行调整,如果调整失败和判断进程不可活, 则调用 appDiedLocked kill 其进程
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
// ....
boolean success = updateOomAdjLocked(cpr.proc);
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
// it, we will check whether the process still exists. Note that this doesn't
// completely get rid of races with LMK killing the process, but should make
// them much smaller.
if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
success = false;
}
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
// NOTE: there is still a race here where a signal could be
// pending on the process even though we managed to update its
// adj level. Not sure what to do about this, but at least
// the race is now smaller.
if (!success) {
// Uh oh... it looks like the provider's process
// has been killed on us. We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
checkTime(startTime, "getContentProviderImpl: before appDied");
appDiedLocked(cpr.proc);
checkTime(startTime, "getContentProviderImpl: after appDied");
if (!lastRef) {
// This wasn't the last ref our process had on
// the provider... we have now been killed, bail.
return null;
}
providerRunning = false;
conn = null;
} else {
cpr.proc.verifiedAdj = cpr.proc.setAdj;
}
其实最后之所以把文章标题写为随笔,就是还有未完成的事情要做。
虽然把 1 的疑问找到地方了,但是其实是引出来了更多疑问,什么时候调用,其他层逻辑实现
转一篇文章看看 Android开发——MediaProvider源码分析(1)
同样2 也是,OomAdj 为什么会调整失败,调整失败后怎么做 等等...
这些都是会引发新的思考,并且跟自身已有的知识点联系起来,所以系统知识技能需要不断思考,实践学习
网友评论