diff options
| -rw-r--r-- | core/java/android/os/IMountService.aidl | 5 | ||||
| -rw-r--r-- | core/java/android/os/Power.java | 18 | ||||
| -rw-r--r-- | core/java/com/android/internal/app/ShutdownThread.java | 16 | ||||
| -rw-r--r-- | core/jni/android_os_Power.cpp | 2 | ||||
| -rw-r--r-- | services/java/com/android/server/MountService.java | 75 |
5 files changed, 113 insertions, 3 deletions
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl index 96d44b6441dd..4491a8ae56f7 100644 --- a/core/java/android/os/IMountService.aidl +++ b/core/java/android/os/IMountService.aidl @@ -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(); } diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java index 3679e478126e..bc76180acab8 100644 --- a/core/java/android/os/Power.java +++ b/core/java/android/os/Power.java @@ -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 ; } diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java index 2060cf8a7ad1..c110f9545933 100644 --- a/core/java/com/android/internal/app/ShutdownThread.java +++ b/core/java/com/android/internal/app/ShutdownThread.java @@ -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; @@ -189,6 +190,10 @@ public final class ShutdownThread extends Thread { final IBluetooth bluetooth = IBluetooth.Stub.asInterface(ServiceManager.checkService( BluetoothAdapter.BLUETOOTH_SERVICE)); + + final IMountService mount = + IMountService.Stub.asInterface( + ServiceManager.checkService("mount")); try { bluetoothOff = bluetooth == null || @@ -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(); diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp index df5edba4eb76..a46c2dd5b90a 100644 --- a/core/jni/android_os_Power.cpp +++ b/core/jni/android_os_Power.cpp @@ -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) diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 204389e8601d..ddf7c56d1e05 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -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. */ |