Home | History | Annotate | Download | only in storage
      1 package com.android.internal.os.storage;
      2 
      3 import android.app.ProgressDialog;
      4 import android.app.Service;
      5 import android.content.ComponentName;
      6 import android.content.Context;
      7 import android.content.DialogInterface;
      8 import android.content.Intent;
      9 import android.os.Environment;
     10 import android.os.IBinder;
     11 import android.os.PowerManager;
     12 import android.os.RemoteException;
     13 import android.os.ServiceManager;
     14 import android.os.storage.IMountService;
     15 import android.os.storage.StorageEventListener;
     16 import android.os.storage.StorageManager;
     17 import android.util.Log;
     18 import android.view.WindowManager;
     19 import android.widget.Toast;
     20 
     21 import com.android.internal.R;
     22 
     23 /**
     24  * Takes care of unmounting and formatting external storage.
     25  */
     26 public class ExternalStorageFormatter extends Service
     27         implements DialogInterface.OnCancelListener {
     28     static final String TAG = "ExternalStorageFormatter";
     29 
     30     public static final String FORMAT_ONLY = "com.android.internal.os.storage.FORMAT_ONLY";
     31     public static final String FORMAT_AND_FACTORY_RESET = "com.android.internal.os.storage.FORMAT_AND_FACTORY_RESET";
     32 
     33     public static final String EXTRA_ALWAYS_RESET = "always_reset";
     34 
     35     public static final ComponentName COMPONENT_NAME
     36             = new ComponentName("android", ExternalStorageFormatter.class.getName());
     37 
     38     // Access using getMountService()
     39     private IMountService mMountService = null;
     40 
     41     private StorageManager mStorageManager = null;
     42 
     43     private PowerManager.WakeLock mWakeLock;
     44 
     45     private ProgressDialog mProgressDialog = null;
     46 
     47     private boolean mFactoryReset = false;
     48     private boolean mAlwaysReset = false;
     49 
     50     StorageEventListener mStorageListener = new StorageEventListener() {
     51         @Override
     52         public void onStorageStateChanged(String path, String oldState, String newState) {
     53             Log.i(TAG, "Received storage state changed notification that " +
     54                     path + " changed state from " + oldState +
     55                     " to " + newState);
     56             updateProgressState();
     57         }
     58     };
     59 
     60     @Override
     61     public void onCreate() {
     62         super.onCreate();
     63 
     64         if (mStorageManager == null) {
     65             mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
     66             mStorageManager.registerListener(mStorageListener);
     67         }
     68 
     69         mWakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE))
     70                 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExternalStorageFormatter");
     71         mWakeLock.acquire();
     72     }
     73 
     74     @Override
     75     public int onStartCommand(Intent intent, int flags, int startId) {
     76         if (FORMAT_AND_FACTORY_RESET.equals(intent.getAction())) {
     77             mFactoryReset = true;
     78         }
     79         if (intent.getBooleanExtra(EXTRA_ALWAYS_RESET, false)) {
     80             mAlwaysReset = true;
     81         }
     82 
     83         if (mProgressDialog == null) {
     84             mProgressDialog = new ProgressDialog(this);
     85             mProgressDialog.setIndeterminate(true);
     86             mProgressDialog.setCancelable(true);
     87             mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
     88             if (!mAlwaysReset) {
     89                 mProgressDialog.setOnCancelListener(this);
     90             }
     91             updateProgressState();
     92             mProgressDialog.show();
     93         }
     94 
     95         return Service.START_REDELIVER_INTENT;
     96     }
     97 
     98     @Override
     99     public void onDestroy() {
    100         if (mStorageManager != null) {
    101             mStorageManager.unregisterListener(mStorageListener);
    102         }
    103         if (mProgressDialog != null) {
    104             mProgressDialog.dismiss();
    105         }
    106         mWakeLock.release();
    107         super.onDestroy();
    108     }
    109 
    110     @Override
    111     public IBinder onBind(Intent intent) {
    112         return null;
    113     }
    114 
    115     @Override
    116     public void onCancel(DialogInterface dialog) {
    117         IMountService mountService = getMountService();
    118         String extStoragePath = Environment.getExternalStorageDirectory().toString();
    119         try {
    120             mountService.mountVolume(extStoragePath);
    121         } catch (RemoteException e) {
    122             Log.w(TAG, "Failed talking with mount service", e);
    123         }
    124         stopSelf();
    125     }
    126 
    127     void fail(int msg) {
    128         Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
    129         if (mAlwaysReset) {
    130             sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
    131         }
    132         stopSelf();
    133     }
    134 
    135     void updateProgressState() {
    136         String status = Environment.getExternalStorageState();
    137         if (Environment.MEDIA_MOUNTED.equals(status)
    138                 || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status)) {
    139             updateProgressDialog(R.string.progress_unmounting);
    140             IMountService mountService = getMountService();
    141             String extStoragePath = Environment.getExternalStorageDirectory().toString();
    142             try {
    143                 mountService.unmountVolume(extStoragePath, true);
    144             } catch (RemoteException e) {
    145                 Log.w(TAG, "Failed talking with mount service", e);
    146             }
    147         } else if (Environment.MEDIA_NOFS.equals(status)
    148                 || Environment.MEDIA_UNMOUNTED.equals(status)
    149                 || Environment.MEDIA_UNMOUNTABLE.equals(status)) {
    150             updateProgressDialog(R.string.progress_erasing);
    151             final IMountService mountService = getMountService();
    152             final String extStoragePath = Environment.getExternalStorageDirectory().toString();
    153             if (mountService != null) {
    154                 new Thread() {
    155                     public void run() {
    156                         boolean success = false;
    157                         try {
    158                             mountService.formatVolume(extStoragePath);
    159                             success = true;
    160                         } catch (Exception e) {
    161                             Toast.makeText(ExternalStorageFormatter.this,
    162                                     R.string.format_error, Toast.LENGTH_LONG).show();
    163                         }
    164                         if (success) {
    165                             if (mFactoryReset) {
    166                                 sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
    167                                 // Intent handling is asynchronous -- assume it will happen soon.
    168                                 stopSelf();
    169                                 return;
    170                             }
    171                         }
    172                         // If we didn't succeed, or aren't doing a full factory
    173                         // reset, then it is time to remount the storage.
    174                         if (!success && mAlwaysReset) {
    175                             sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
    176                         } else {
    177                             try {
    178                                 mountService.mountVolume(extStoragePath);
    179                             } catch (RemoteException e) {
    180                                 Log.w(TAG, "Failed talking with mount service", e);
    181                             }
    182                         }
    183                         stopSelf();
    184                         return;
    185                     }
    186                 }.start();
    187             } else {
    188                 Log.w("MediaFormat", "Unable to locate IMountService");
    189             }
    190         } else if (Environment.MEDIA_BAD_REMOVAL.equals(status)) {
    191             fail(R.string.media_bad_removal);
    192         } else if (Environment.MEDIA_CHECKING.equals(status)) {
    193             fail(R.string.media_checking);
    194         } else if (Environment.MEDIA_REMOVED.equals(status)) {
    195             fail(R.string.media_removed);
    196         } else if (Environment.MEDIA_SHARED.equals(status)) {
    197             fail(R.string.media_shared);
    198         } else {
    199             fail(R.string.media_unknown_state);
    200             Log.w(TAG, "Unknown storage state: " + status);
    201             stopSelf();
    202         }
    203     }
    204 
    205     public void updateProgressDialog(int msg) {
    206         if (mProgressDialog == null) {
    207             mProgressDialog = new ProgressDialog(this);
    208             mProgressDialog.setIndeterminate(true);
    209             mProgressDialog.setCancelable(false);
    210             mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    211             mProgressDialog.show();
    212         }
    213 
    214         mProgressDialog.setMessage(getText(msg));
    215     }
    216 
    217     IMountService getMountService() {
    218         if (mMountService == null) {
    219             IBinder service = ServiceManager.getService("mount");
    220             if (service != null) {
    221                 mMountService = IMountService.Stub.asInterface(service);
    222             } else {
    223                 Log.e(TAG, "Can't get mount service");
    224             }
    225         }
    226         return mMountService;
    227     }
    228 }
    229