summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/IMountService.aidl5
-rw-r--r--core/java/android/os/Power.java18
-rw-r--r--core/java/com/android/internal/app/ShutdownThread.java16
-rw-r--r--core/jni/android_os_Power.cpp2
-rw-r--r--services/java/com/android/server/MountService.java75
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.
*/