• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
onCreate()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
onStartCommand(Intent intent, int flags, int startId)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
onDestroy()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
onBind(Intent intent)111     public IBinder onBind(Intent intent) {
112         return null;
113     }
114 
115     @Override
onCancel(DialogInterface dialog)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 
fail(int msg)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 
updateProgressState()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 
updateProgressDialog(int msg)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 
getMountService()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