packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java
负责接收外界发来的请求扫描
private void scan(Context context, String volume) {
Bundle args = new Bundle();
args.putString("volume", volume);
context.startService(
new Intent(context, MediaScannerService.class).putExtras(args));
}
private void scanFile(Context context, String path) {
Bundle args = new Bundle();
args.putString("filepath", path);
context.startService(
new Intent(context, MediaScannerService.class).putExtras(args));
}
启动服务
packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerService.java
@Override
public void onCreate()
{
//
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
StorageManager storageManager = (StorageManager)getSystemService(Context.STORAGE_SERVICE);
mExternalStoragePaths = storageManager.getVolumePaths();
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block.
Thread thr = new Thread(null, this, "MediaScannerService");
thr.start();
}
工作线程
public void run()
{
// reduce priority below other background threads to avoid interfering
// with other services at boot time.
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND +
Process.THREAD_PRIORITY_LESS_FAVORABLE);
Looper.prepare();
mServiceLooper = Looper.myLooper();
mServiceHandler = new ServiceHandler();
Looper.loop();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
while (mServiceHandler == null) {
synchronized (this) {
try {
wait(100);
} catch (InterruptedException e) {
}
}
}
if (intent == null) {
Log.e(TAG, "Intent is null in onStartCommand: ",
new NullPointerException());
return Service.START_NOT_STICKY;
}
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent.getExtras();
mServiceHandler.sendMessage(msg);
// Try again later if we are killed before we can finish scanning.
return Service.START_REDELIVER_INTENT;
}
handler处理消息
private final class ServiceHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
Bundle arguments = (Bundle) msg.obj;
String filePath = arguments.getString("filepath");
try {
if (filePath != null) {
IBinder binder = arguments.getIBinder("listener");
IMediaScannerListener listener =
(binder == null ? null : IMediaScannerListener.Stub.asInterface(binder));
Uri uri = null;
try {
uri = scanFile(filePath, arguments.getString("mimetype"));
} catch (Exception e) {
Log.e(TAG, "Exception scanning file", e);
}
if (listener != null) {
listener.scanCompleted(filePath, uri);
}
} else {
String volume = arguments.getString("volume");
String[] directories = null;
if (MediaProvider.INTERNAL_VOLUME.equals(volume)) {
// scan internal media storage
directories = new String[] {
Environment.getRootDirectory() + "/media",
};
}
else if (MediaProvider.EXTERNAL_VOLUME.equals(volume)) {
// scan external storage volumes
directories = mExternalStoragePaths;
}
if (directories != null) {
if (false) Log.d(TAG, "start scanning volume " + volume + ": "
+ Arrays.toString(directories));
scan(directories, volume);
if (false) Log.d(TAG, "done scanning volume " + volume);
}
}
} catch (Exception e) {
Log.e(TAG, "Exception in handleMessage", e);
}
stopSelf(msg.arg1);
}
};
static final String INTERNAL_VOLUME = "internal";//内部
static final String EXTERNAL_VOLUME = "external";//外部
获取文件夹路径后扫描
private void scan(String[] directories, String volumeName) {
Uri uri = Uri.parse("file://" + directories[0]);
// don't sleep while scanning
mWakeLock.acquire();
try {
ContentValues values = new ContentValues();
values.put(MediaStore.MEDIA_SCANNER_VOLUME, volumeName);
Uri scanUri = getContentResolver().insert(MediaStore.getMediaScannerUri(), values);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri));
try {
if (volumeName.equals(MediaProvider.EXTERNAL_VOLUME)) {
openDatabase(volumeName);
}
MediaScanner scanner = createMediaScanner();
scanner.scanDirectories(directories, volumeName);
} catch (Exception e) {
Log.e(TAG, "exception in MediaScanner.scan()", e);
}
getContentResolver().delete(scanUri, null, null);
} finally {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri));
mWakeLock.release();
}
}
创建MediaScanner
private MediaScanner createMediaScanner() {
MediaScanner scanner = new MediaScanner(this);
Locale locale = getResources().getConfiguration().locale;
if (locale != null) {
String language = locale.getLanguage();
String country = locale.getCountry();
String localeString = null;
if (language != null) {
if (country != null) {
scanner.setLocale(language + "_" + country);
} else {
scanner.setLocale(language);
}
}
}
return scanner;
}
frameworks/base/media/java/android/media/MediaScanner.java
主要扫描工作
public void scanDirectories(String[] directories, String volumeName) {
try {
long start = System.currentTimeMillis();
initialize(volumeName);
prescan(null, true);
long prescan = System.currentTimeMillis();
if (ENABLE_BULK_INSERTS) {
// create MediaInserter for bulk inserts
mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
}
for (int i = 0; i < directories.length; i++) {
processDirectory(directories[i]