Merge "framework: storage: Ensure that filesystems are unmounted before shutdown/reboot" into eclair
This commit is contained in:
@ -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,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 ;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user