am c93c70c4: Merge "framework: storage: Ensure that filesystems are unmounted before shutdown/reboot" into eclair

Merge commit 'c93c70c4b849d31ff1b5e5cf2fb9462fd60e5da0' into eclair-plus-aosp

* commit 'c93c70c4b849d31ff1b5e5cf2fb9462fd60e5da0':
  framework: storage: Ensure that filesystems are unmounted before shutdown/reboot
This commit is contained in:
San Mehat
2010-01-12 10:02:40 -08:00
committed by Android Git Automerger
5 changed files with 113 additions and 3 deletions

View File

@ -75,4 +75,9 @@ interface IMountService
* when a UMS host is detected. * when a UMS host is detected.
*/ */
void setAutoStartUms(boolean value); void setAutoStartUms(boolean value);
/**
* Shuts down the MountService and gracefully unmounts all external media.
*/
void shutdown();
} }

View File

@ -17,6 +17,8 @@
package android.os; package android.os;
import java.io.IOException; import java.io.IOException;
import android.os.ServiceManager;
import android.os.IMountService;
/** /**
* Class that provides access to some of the power management functions. * 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 * @throws IOException if reboot fails for some reason (eg, lack of
* permission) * 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 ;
} }

View File

@ -32,6 +32,7 @@ import android.os.RemoteException;
import android.os.Power; import android.os.Power;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.os.IMountService;
import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.ITelephony;
import android.util.Log; import android.util.Log;
@ -190,6 +191,10 @@ public final class ShutdownThread extends Thread {
IBluetooth.Stub.asInterface(ServiceManager.checkService( IBluetooth.Stub.asInterface(ServiceManager.checkService(
BluetoothAdapter.BLUETOOTH_SERVICE)); BluetoothAdapter.BLUETOOTH_SERVICE));
final IMountService mount =
IMountService.Stub.asInterface(
ServiceManager.checkService("mount"));
try { try {
bluetoothOff = bluetooth == null || bluetoothOff = bluetooth == null ||
bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF; bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
@ -241,6 +246,17 @@ public final class ShutdownThread extends Thread {
SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC); 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 //shutdown power
Log.i(TAG, "Performing low-level shutdown..."); Log.i(TAG, "Performing low-level shutdown...");
Power.shutdown(); Power.shutdown();

View File

@ -105,7 +105,7 @@ static JNINativeMethod method_table[] = {
{ "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout }, { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },
{ "setScreenState", "(Z)I", (void*)setScreenState }, { "setScreenState", "(Z)I", (void*)setScreenState },
{ "shutdown", "()V", (void*)android_os_Power_shutdown }, { "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) int register_android_os_Power(JNIEnv *env)

View File

@ -108,13 +108,86 @@ class MountService extends IMountService.Stub {
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) { 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 thread = new Thread(mListener, MountListener.class.getName());
thread.start(); 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. * @return true if USB mass storage support is enabled.
*/ */