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