今天分析setting中直接格式化的流程,直接上代码:
Setting中的MediaFormat.java中的mFinalClickListener 这个回调,就是调用Format的地方:其是其了一个Service。
private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
public void onClick(View v) {
if (Utils.isMonkeyRunning()) {
return;
}
Intent intent = new Intent(ExternalStorageFormatter.FORMAT_ONLY);
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
// Transfer the storage volume to the new intent
final StorageVolume storageVolume = getIntent().getParcelableExtra(
StorageVolume.EXTRA_STORAGE_VOLUME);
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, storageVolume);
startService(intent);
finish();
}
};
ExternalStorageFormatter.java就是这个Service,Service刚建立调用onCreate函数,起来在MountService中注册了回调,然后持一个睡眠锁。
StorageEventListener mStorageListener = new StorageEventListener() {//放在MountService中的回调
@Override
public void onStorageStateChanged(String path, String oldState, String newState) {
Log.i(TAG, "Received storage state changed notification that " +
path + " changed state from " + oldState +
" to " + newState);
updateProgressState();//updateProgressState(主要的函数)
}
};
@Override
public void onCreate() {
super.onCreate();
if (mStorageManager == null) {
mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
mStorageManager.registerListener(mStorageListener);
}
mWakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExternalStorageFormatter");
mWakeLock.acquire();
}
调用了onCreate之后,会调用onStartCommand函数
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (FORMAT_AND_FACTORY_RESET.equals(intent.getAction())) {
mFactoryReset = true;
}
if (intent.getBooleanExtra(EXTRA_ALWAYS_RESET, false)) {
mAlwaysReset = true;
}
mReason = intent.getStringExtra(Intent.EXTRA_REASON);
mStorageVolume = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);//获取StorageVolume
if (mProgressDialog == null) {//第一次调用的时候,新建一个Dialog
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(true);
mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
if (!mAlwaysReset) {
mProgressDialog.setOnCancelListener(this);
}
updateProgressState();//第一次调用updateProgressState
mProgressDialog.show();
}
return Service.START_REDELIVER_INTENT;
}
下面我们就来分析下主要的函数,第一次会将其卸载,然后MountService会将其Volume的状态改变,并且通知回调函数来调用updateProgressState函数。第二次过来已经是unmounted了,这时候将其格式化,最后再挂载sd卡。
void updateProgressState() {
String status = mStorageVolume == null ?
Environment.getExternalStorageState() :
mStorageManager.getVolumeState(mStorageVolume.getPath());
if (Environment.MEDIA_MOUNTED.equals(status)//第一次调用的时候,发现Volume是mounted,就将它卸载
|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(status)) {
updateProgressDialog(R.string.progress_unmounting);
IMountService mountService = getMountService();
final String extStoragePath = mStorageVolume == null ?
Environment.getLegacyExternalStorageDirectory().toString() :
mStorageVolume.getPath();
try {
// Remove encryption mapping if this is an unmount for a factory reset.
mountService.unmountVolume(extStoragePath, true, mFactoryReset);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with mount service", e);
}
} else if (Environment.MEDIA_NOFS.equals(status)
|| Environment.MEDIA_UNMOUNTED.equals(status)
|| Environment.MEDIA_UNMOUNTABLE.equals(status)) {//当第二次回调过来,应该是已经卸载了,这时候再去格式化;由于format耗时其了一个thread
updateProgressDialog(R.string.progress_erasing);
final IMountService mountService = getMountService();
final String extStoragePath = mStorageVolume == null ?
Environment.getLegacyExternalStorageDirectory().toString() :
mStorageVolume.getPath();
if (mountService != null) {
new Thread() {
@Override
public void run() {
boolean success = false;
try {
mountService.formatVolume(extStoragePath);
success = true;
} catch (Exception e) {
Toast.makeText(ExternalStorageFormatter.this,
R.string.format_error, Toast.LENGTH_LONG).show();
}
if (success) {
if (mFactoryReset) {
Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_REASON, mReason);
sendBroadcast(intent);
// Intent handling is asynchronous -- assume it will happen soon.
stopSelf();
return;
}
}
// If we didn't succeed, or aren't doing a full factory
// reset, then it is time to remount the storage.
if (!success && mAlwaysReset) {
Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_REASON, mReason);
sendBroadcast(intent);
} else {//格式化完后再挂载SD卡
try {
mountService.mountVolume(extStoragePath);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with mount service", e);
}
}
stopSelf();//最后将Service暂停了
return;
}
}.start();
} else {
Log.w(TAG, "Unable to locate IMountService");
}
} else if (Environment.MEDIA_BAD_REMOVAL.equals(status)) {
fail(R.string.media_bad_removal);
} else if (Environment.MEDIA_CHECKING.equals(status)) {
fail(R.string.media_checking);
} else if (Environment.MEDIA_REMOVED.equals(status)) {
fail(R.string.media_removed);
} else if (Environment.MEDIA_SHARED.equals(status)) {
fail(R.string.media_shared);
} else {//如果发过来的状态不对,直接停止Service
fail(R.string.media_unknown_state);
Log.w(TAG, "Unknown storage state: " + status);
stopSelf();
}
}
调完Format,紧接着就调mount,会不会有问题。因为这几个函数都是阻塞的,一定要等vold执行完,才结束,所以连续调也不会有问题,但是一定要起线程。