Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16c9c249 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Fix up ExternalStorageFormatter.

It's not going to be around for much longer, so just fix enough to
work correctly.

Also teach about new "unmountable" state from vold.

Bug: 19993667
Change-Id: Ib72c3e134092b2a895389dd5b056f4bb8043709a
parent 7151a9a8
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -57,6 +57,7 @@ public class VolumeInfo implements Parcelable {
    public static final int STATE_MOUNTED = 2;
    public static final int STATE_MOUNTED = 2;
    public static final int STATE_FORMATTING = 3;
    public static final int STATE_FORMATTING = 3;
    public static final int STATE_UNMOUNTING = 4;
    public static final int STATE_UNMOUNTING = 4;
    public static final int STATE_UNMOUNTABLE = 5;


    public static final int FLAG_PRIMARY = 1 << 0;
    public static final int FLAG_PRIMARY = 1 << 0;
    public static final int FLAG_VISIBLE = 1 << 1;
    public static final int FLAG_VISIBLE = 1 << 1;
@@ -70,11 +71,13 @@ public class VolumeInfo implements Parcelable {
        sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
        sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
        sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
        sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTABLE, Environment.MEDIA_UNMOUNTABLE);


        sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
        sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
        sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
        sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
        sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
        sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
        sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
        sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
        sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE);
    }
    }


    /** vold state */
    /** vold state */
+62 −175
Original line number Original line Diff line number Diff line
@@ -4,18 +4,12 @@ import android.app.ProgressDialog;
import android.app.Service;
import android.app.Service;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IMountService;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.os.storage.StorageVolume;
import android.util.Log;
import android.util.Slog;
import android.view.WindowManager;
import android.view.WindowManager;
import android.widget.Toast;
import android.widget.Toast;


@@ -24,8 +18,7 @@ import com.android.internal.R;
/**
/**
 * Takes care of unmounting and formatting external storage.
 * Takes care of unmounting and formatting external storage.
 */
 */
public class ExternalStorageFormatter extends Service
public class ExternalStorageFormatter extends Service {
        implements DialogInterface.OnCancelListener {
    static final String TAG = "ExternalStorageFormatter";
    static final String TAG = "ExternalStorageFormatter";


    public static final String FORMAT_ONLY = "com.android.internal.os.storage.FORMAT_ONLY";
    public static final String FORMAT_ONLY = "com.android.internal.os.storage.FORMAT_ONLY";
@@ -33,16 +26,10 @@ public class ExternalStorageFormatter extends Service


    public static final String EXTRA_ALWAYS_RESET = "always_reset";
    public static final String EXTRA_ALWAYS_RESET = "always_reset";


    // If non-null, the volume to format. Otherwise, will use the default external storage directory
    private StorageVolume mStorageVolume;

    public static final ComponentName COMPONENT_NAME
    public static final ComponentName COMPONENT_NAME
            = new ComponentName("android", ExternalStorageFormatter.class.getName());
            = new ComponentName("android", ExternalStorageFormatter.class.getName());


    // Access using getMountService()
    private StorageManager mStorageManager;
    private IMountService mMountService = null;

    private StorageManager mStorageManager = null;


    private PowerManager.WakeLock mWakeLock;
    private PowerManager.WakeLock mWakeLock;


@@ -52,24 +39,11 @@ public class ExternalStorageFormatter extends Service
    private boolean mAlwaysReset = false;
    private boolean mAlwaysReset = false;
    private String mReason = null;
    private String mReason = null;


    StorageEventListener mStorageListener = new StorageEventListener() {
        @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();
        }
    };

    @Override
    @Override
    public void onCreate() {
    public void onCreate() {
        super.onCreate();
        super.onCreate();


        if (mStorageManager == null) {
        mStorageManager = getSystemService(StorageManager.class);
            mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
            mStorageManager.registerListener(mStorageListener);
        }


        mWakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE))
        mWakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE))
                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExternalStorageFormatter");
                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExternalStorageFormatter");
@@ -86,99 +60,40 @@ public class ExternalStorageFormatter extends Service
        }
        }


        mReason = intent.getStringExtra(Intent.EXTRA_REASON);
        mReason = intent.getStringExtra(Intent.EXTRA_REASON);
        mStorageVolume = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
        StorageVolume userVol = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
        if (userVol == null) {
            Slog.w(TAG, "Missing explicit storage volume; assuming default");
            userVol = mStorageManager.getPrimaryVolume();
        }

        final String volumeId = userVol.getId();


        if (mProgressDialog == null) {
        mProgressDialog = new ProgressDialog(this);
        mProgressDialog = new ProgressDialog(this);
        mProgressDialog.setIndeterminate(true);
        mProgressDialog.setIndeterminate(true);
            mProgressDialog.setCancelable(true);
        mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
            if (!mAlwaysReset) {
        mProgressDialog.setMessage(getText(R.string.progress_unmounting));
                mProgressDialog.setOnCancelListener(this);
            }
            updateProgressState();
        mProgressDialog.show();
        mProgressDialog.show();
        }

        new FormatTask(volumeId).start();


        return Service.START_REDELIVER_INTENT;
        return Service.START_REDELIVER_INTENT;
    }
    }


    @Override
    private class FormatTask extends Thread {
    public void onDestroy() {
        private final String mVolumeId;
        if (mStorageManager != null) {
            mStorageManager.unregisterListener(mStorageListener);
        }
        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
        }
        mWakeLock.release();
        super.onDestroy();
    }


    @Override
        public FormatTask(String volumeId) {
    public IBinder onBind(Intent intent) {
            mVolumeId = volumeId;
        return null;
        }
        }


    @Override
    public void onCancel(DialogInterface dialog) {
        IMountService mountService = getMountService();
        String extStoragePath = mStorageVolume == null ?
                Environment.getLegacyExternalStorageDirectory().toString() :
                mStorageVolume.getPath();
        try {
            mountService.mountVolume(extStoragePath);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed talking with mount service", e);
        }
        stopSelf();
    }

    void fail(int msg) {
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
        if (mAlwaysReset) {
            Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
            intent.putExtra(Intent.EXTRA_REASON, mReason);
            sendBroadcast(intent);
        }
        stopSelf();
    }

    void updateProgressState() {
        String status = mStorageVolume == null ?
                Environment.getExternalStorageState() :
                mStorageManager.getVolumeState(mStorageVolume.getPath());
        if (Environment.MEDIA_MOUNTED.equals(status)
                || 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)) {
            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
        @Override
        public void run() {
        public void run() {
            boolean success = false;
            boolean success = false;
            try {
            try {
                            mountService.formatVolume(extStoragePath);
                mStorageManager.format(mVolumeId);
                success = true;
                success = true;
            } catch (Exception e) {
            } catch (Exception e) {
                Slog.w(TAG, "Failed to format", e);
                Toast.makeText(ExternalStorageFormatter.this,
                Toast.makeText(ExternalStorageFormatter.this,
                        R.string.format_error, Toast.LENGTH_LONG).show();
                        R.string.format_error, Toast.LENGTH_LONG).show();
            }
            }
@@ -202,54 +117,26 @@ public class ExternalStorageFormatter extends Service
                sendBroadcast(intent);
                sendBroadcast(intent);
            } else {
            } else {
                try {
                try {
                                mountService.mountVolume(extStoragePath);
                    mStorageManager.mount(mVolumeId);
                            } catch (RemoteException e) {
                } catch (Exception e) {
                                Log.w(TAG, "Failed talking with mount service", e);
                    Slog.w(TAG, "Failed to mount", e);
                            }
                }
                }
                        stopSelf();
                        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 {
            fail(R.string.media_unknown_state);
            Log.w(TAG, "Unknown storage state: " + status);
            stopSelf();
            stopSelf();
        }
        }
    }
    }


    public void updateProgressDialog(int msg) {
    @Override
        if (mProgressDialog == null) {
    public void onDestroy() {
            mProgressDialog = new ProgressDialog(this);
        if (mProgressDialog != null) {
            mProgressDialog.setIndeterminate(true);
            mProgressDialog.dismiss();
            mProgressDialog.setCancelable(false);
            mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
            mProgressDialog.show();
        }
        }

        mWakeLock.release();
        mProgressDialog.setMessage(getText(msg));
        super.onDestroy();
    }
    }


    IMountService getMountService() {
    @Override
        if (mMountService == null) {
    public IBinder onBind(Intent intent) {
            IBinder service = ServiceManager.getService("mount");
        return null;
            if (service != null) {
                mMountService = IMountService.Stub.asInterface(service);
            } else {
                Log.e(TAG, "Can't get mount service");
            }
        }
        return mMountService;
    }
    }
}
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -3125,6 +3125,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }
    }


    private void wipeDataLocked(boolean wipeExtRequested, String reason) {
    private void wipeDataLocked(boolean wipeExtRequested, String reason) {
        // TODO: wipe all public volumes on device

        // If the SD card is encrypted and non-removable, we have to force a wipe.
        // If the SD card is encrypted and non-removable, we have to force a wipe.
        boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
        boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();