Add new shutdown observer for MountService.

Use new observer before rebooting and shutting down.
Add some unit tests for unmount and shutdown code paths
Fix registering/unregistering part in MountService
Use ShutdownThread in PowerManager.reboot()
Add reboot support to ShutdownThread.
Remove MountService code from PowerManagerService.java and Power.java.
Clean shutdown/reboot is handled exclusively by ShutdownThread now.

Change-Id: Iefb157451d3d9c426cb431707b870a873c09123d
This commit is contained in:
Suchi Amalapurapu
2010-03-08 14:48:40 -08:00
committed by Mike Lockwood
parent 8e461c9add
commit 6ffce2e9a3
10 changed files with 490 additions and 108 deletions

View File

@@ -18,7 +18,6 @@ package android.os;
import java.io.IOException;
import android.os.ServiceManager;
import android.os.storage.IMountService;
/**
* Class that provides access to some of the power management functions.
@@ -101,15 +100,6 @@ public class Power
*/
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);
}

View File

@@ -18,6 +18,7 @@
package android.os.storage;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
/** WARNING! Update IMountService.h and IMountService.cpp if you change this file.
* In particular, the ordering of the methods below must match the
@@ -142,6 +143,7 @@ interface IMountService
/**
* Shuts down the MountService and gracefully unmounts all external media.
* Invokes call back once the shutdown is complete.
*/
void shutdown();
void shutdown(IMountShutdownObserver observer);
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.storage;
/**
* Callback class for receiving events related
* to shutdown.
*
* @hide - For internal consumption only.
*/
interface IMountShutdownObserver {
/**
* This method is called when the shutdown
* of MountService completed.
* @param statusCode indicates success or failure
* of the shutdown.
*/
void onShutDownComplete(int statusCode);
}

View File

@@ -28,12 +28,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.os.Power;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Power;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.storage.IMountService;
import android.os.storage.IMountShutdownObserver;
import com.android.internal.telephony.ITelephony;
import android.util.Log;
@@ -46,16 +47,20 @@ public final class ShutdownThread extends Thread {
private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
// maximum time we wait for the shutdown broadcast before going on.
private static final int MAX_BROADCAST_TIME = 10*1000;
private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
// state tracking
private static Object sIsStartedGuard = new Object();
private static boolean sIsStarted = false;
private static boolean mReboot;
private static String mRebootReason;
// static instance of this thread
private static final ShutdownThread sInstance = new ShutdownThread();
private final Object mBroadcastDoneSync = new Object();
private boolean mBroadcastDone;
private final Object mActionDoneSync = new Object();
private boolean mActionDone;
private Context mContext;
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
@@ -64,12 +69,13 @@ public final class ShutdownThread extends Thread {
private ShutdownThread() {
}
/**
/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
* is shown.
*
*
* @param context Context used to display the shutdown progress dialog.
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void shutdown(final Context context, boolean confirm) {
// ensure that only one thread is trying to power down.
@@ -106,6 +112,21 @@ public final class ShutdownThread extends Thread {
}
}
/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
* is shown.
*
* @param context Context used to display the shutdown progress dialog.
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootReason = reason;
shutdown(context, confirm);
}
private static void beginShutdownSequence(Context context) {
synchronized (sIsStartedGuard) {
sIsStarted = true;
@@ -145,13 +166,13 @@ public final class ShutdownThread extends Thread {
sInstance.start();
}
void broadcastDone() {
synchronized (mBroadcastDoneSync) {
mBroadcastDone = true;
mBroadcastDoneSync.notifyAll();
void actionDone() {
synchronized (mActionDoneSync) {
mActionDone = true;
mActionDoneSync.notifyAll();
}
}
/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
@@ -163,27 +184,27 @@ public final class ShutdownThread extends Thread {
BroadcastReceiver br = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// We don't allow apps to cancel this, so ignore the result.
broadcastDone();
actionDone();
}
};
Log.i(TAG, "Sending shutdown broadcast...");
// First send the high-level shut down broadcast.
mBroadcastDone = false;
mActionDone = false;
mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
br, mHandler, 0, null, null);
final long endTime = System.currentTimeMillis() + MAX_BROADCAST_TIME;
synchronized (mBroadcastDoneSync) {
while (!mBroadcastDone) {
synchronized (mActionDoneSync) {
while (!mActionDone) {
long delay = endTime - System.currentTimeMillis();
if (delay <= 0) {
Log.w(TAG, "Shutdown broadcast timed out");
break;
}
try {
mBroadcastDoneSync.wait(delay);
mActionDoneSync.wait(delay);
} catch (InterruptedException e) {
}
}
@@ -262,17 +283,50 @@ public final class ShutdownThread extends Thread {
}
// Shutdown MountService to ensure media is in a safe state
try {
if (mount != null) {
mount.shutdown();
} else {
Log.w(TAG, "MountService unavailable for shutdown");
IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
actionDone();
}
};
Log.i(TAG, "Shutting down MountService");
// Set initial variables and time out time.
mActionDone = false;
final long endShutTime = System.currentTimeMillis() + MAX_SHUTDOWN_WAIT_TIME;
synchronized (mActionDoneSync) {
try {
if (mount != null) {
mount.shutdown(observer);
} else {
Log.w(TAG, "MountService unavailable for shutdown");
}
} catch (Exception e) {
Log.e(TAG, "Exception during MountService shutdown", e);
}
while (!mActionDone) {
long delay = endShutTime - System.currentTimeMillis();
if (delay <= 0) {
Log.w(TAG, "Shutdown wait timed out");
break;
}
try {
mActionDoneSync.wait(delay);
} catch (InterruptedException e) {
}
}
} catch (Exception e) {
Log.e(TAG, "Exception during MountService shutdown", e);
}
//shutdown power
if (mReboot) {
Log.i(TAG, "Rebooting, reason: " + mRebootReason);
try {
Power.reboot(mRebootReason);
} catch (Exception e) {
Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
}
}
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
Power.shutdown();
}