From 91c7761139c0931da0fcbc89bce38cee4b9cc535 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Thu, 7 Jan 2010 10:39:41 -0800 Subject: [PATCH] MountService: Add an ACTION_SHUTDOWN handler and export a method for external shutdown Signed-off-by: San Mehat --- core/java/android/os/IMountService.aidl | 6 ++ .../java/com/android/server/MountService.java | 65 ++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl index 1ea7200901231..2f60c34d0a9c9 100644 --- a/core/java/android/os/IMountService.aidl +++ b/core/java/android/os/IMountService.aidl @@ -115,4 +115,10 @@ interface IMountService */ String[] getSecureCacheList(); + /** + * Shuts down the MountService and gracefully unmounts + * all external media. + */ + void shutdown(); + } diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 1b0b0eb72ffc4..386dc0a175cda 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -115,6 +115,8 @@ class MountService extends IMountService.Stub { // start processing events before we ought-to mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + mContext.registerReceiver(mBroadcastReceiver, + new IntentFilter(Intent.ACTION_SHUTDOWN), null, null); mListener = new MountListener(this); mShowSafeUnmountNotificationWhenUnmounted = false; @@ -126,13 +128,74 @@ 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(); + } else if (action.equals(Intent.ACTION_SHUTDOWN)) { + shutdown(); } } }; + 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); + } catch (Exception e) { + Log.e(TAG, "external storage unmount failed", e); + } + } + } + /** * @return true if USB mass storage support is enabled. */