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

Commit 7ebf0176 authored by San Mehat's avatar San Mehat
Browse files

framework: storage: Ensure that filesystems are unmounted before shutdown/reboot



Signed-off-by: default avatarSan Mehat <san@google.com>
parent 595f48b2
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -75,4 +75,9 @@ interface IMountService
     * when a UMS host is detected.
     */
    void setAutoStartUms(boolean value);

    /**
     * Shuts down the MountService and gracefully unmounts all external media.
     */
    void shutdown();
}
+17 −1
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package android.os;

import java.io.IOException;
import android.os.ServiceManager;
import android.os.IMountService;

/**
 * Class that provides access to some of the power management functions.
@@ -97,5 +99,19 @@ public class Power
     * @throws IOException if reboot fails for some reason (eg, lack of
     *         permission)
     */
    public static native void reboot(String reason) throws IOException;
    public static void reboot(String reason) throws IOException
    {
        IMountService mSvc = IMountService.Stub.asInterface(
                ServiceManager.getService("mount"));

        if (mSvc != null) {
            try {
                mSvc.shutdown();
            } catch (Exception e) {
            }
        }
        rebootNative(reason);
    }

    private static native void rebootNative(String reason) throws IOException ;
}
+16 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.os.RemoteException;
import android.os.Power;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.IMountService;

import com.android.internal.telephony.ITelephony;
import android.util.Log;
@@ -190,6 +191,10 @@ public final class ShutdownThread extends Thread {
                IBluetooth.Stub.asInterface(ServiceManager.checkService(
                        BluetoothAdapter.BLUETOOTH_SERVICE));

        final IMountService mount =
                IMountService.Stub.asInterface(
                        ServiceManager.checkService("mount"));
        
        try {
            bluetoothOff = bluetooth == null ||
                           bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
@@ -241,6 +246,17 @@ public final class ShutdownThread extends Thread {
            SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
        }

        // Shutdown MountService to ensure media is in a safe state
        try {
            if (mount != null) {
                mount.shutdown();
            } else {
                Log.w(TAG, "MountService unavailable for shutdown");
            }
        } catch (Exception e) {
            Log.e(TAG, "Exception during MountService shutdown", e);
        }

        //shutdown power
        Log.i(TAG, "Performing low-level shutdown...");
        Power.shutdown();
+1 −1
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ static JNINativeMethod method_table[] = {
    { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },
    { "setScreenState", "(Z)I", (void*)setScreenState },
    { "shutdown", "()V", (void*)android_os_Power_shutdown },
    { "reboot", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },
    { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },
};

int register_android_os_Power(JNIEnv *env)
+74 −1
Original line number Diff line number Diff line
@@ -108,13 +108,86 @@ class MountService extends IMountService.Stub {

    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            String action = intent.getAction();

            if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
                Thread thread = new Thread(mListener, MountListener.class.getName());
                thread.start();
            }
        }
    };

    public void shutdown() {
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.SHUTDOWN)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Requires SHUTDOWN permission");
        }

        Log.d(TAG, "Shutting down");
        String state = Environment.getExternalStorageState();

        if (state.equals(Environment.MEDIA_SHARED)) {
            /*
             * If the media is currently shared, unshare it.
             * XXX: This is still dangerous!. We should not
             * be rebooting at *all* if UMS is enabled, since
             * the UMS host could have dirty FAT cache entries
             * yet to flush.
             */
            try {
               setMassStorageEnabled(false);
            } catch (Exception e) {
                Log.e(TAG, "ums disable failed", e);
            }
        } else if (state.equals(Environment.MEDIA_CHECKING)) {
            /*
             * If the media is being checked, then we need to wait for
             * it to complete before being able to proceed.
             */
            // XXX: @hackbod - Should we disable the ANR timer here?
            int retries = 30;
            while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException iex) {
                    Log.e(TAG, "Interrupted while waiting for media", iex);
                    break;
                }
                state = Environment.getExternalStorageState();
            }
            if (retries == 0) {
                Log.e(TAG, "Timed out waiting for media to check");
            }
        }

        if (state.equals(Environment.MEDIA_MOUNTED)) {
            /*
             * If the media is mounted, then gracefully unmount it.
             */
            try {
                String m = Environment.getExternalStorageDirectory().toString();
                unmountMedia(m);

                int retries = 12;
                while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException iex) {
                        Log.e(TAG, "Interrupted while waiting for media", iex);
                        break;
                    }
                    state = Environment.getExternalStorageState();
                }
                if (retries == 0) {
                    Log.e(TAG, "Timed out waiting for media to unmount");
            }
            } catch (Exception e) {
                Log.e(TAG, "external storage unmount failed", e);
            }
        }
    }

    /**
     * @return true if USB mass storage support is enabled.
     */