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

@@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
import android.os.storage.StorageResultCode;
import android.os.Handler;
import android.os.Message;
@@ -172,69 +173,110 @@ class MountService extends IMountService.Stub
}
}
class ShutdownCallBack extends UnmountCallBack {
IMountShutdownObserver observer;
ShutdownCallBack(String path, IMountShutdownObserver observer) {
super(path, true);
this.observer = observer;
}
@Override
void handleFinished() {
int ret = doUnmountVolume(path, true);
if (observer != null) {
try {
observer.onShutDownComplete(ret);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException when shutting down");
}
}
}
}
final private Handler mHandler = new Handler() {
ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
boolean mRegistered = false;
void registerReceiver() {
mRegistered = true;
mContext.registerReceiver(mPmReceiver, mPmFilter);
}
void unregisterReceiver() {
mRegistered = false;
mContext.unregisterReceiver(mPmReceiver);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case H_UNMOUNT_PM_UPDATE: {
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
mForceUnmounts.add(ucb);
mContext.registerReceiver(mPmReceiver, mPmFilter);
boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
if (!hasExtPkgs) {
// Unregister right away
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
// Register only if needed.
if (!mRegistered) {
registerReceiver();
boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
if (!hasExtPkgs) {
// Unregister right away
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
}
}
break;
}
case H_UNMOUNT_PM_DONE: {
// Unregister receiver
mContext.unregisterReceiver(mPmReceiver);
UnmountCallBack ucb = mForceUnmounts.get(0);
if (ucb == null || ucb.path == null) {
// Just ignore
return;
// Unregister now.
if (mRegistered) {
unregisterReceiver();
}
String path = ucb.path;
boolean done = false;
if (!ucb.force) {
done = true;
} else {
int pids[] = getStorageUsers(path);
if (pids == null || pids.length == 0) {
int size = mForceUnmounts.size();
int sizeArr[] = new int[size];
int sizeArrN = 0;
for (int i = 0; i < size; i++) {
UnmountCallBack ucb = mForceUnmounts.get(i);
String path = ucb.path;
boolean done = false;
if (!ucb.force) {
done = true;
} else {
// Kill processes holding references first
ActivityManagerService ams = (ActivityManagerService)
ServiceManager.getService("activity");
// Eliminate system process here?
boolean ret = ams.killPidsForMemory(pids);
if (ret) {
// Confirm if file references have been freed.
pids = getStorageUsers(path);
if (pids == null || pids.length == 0) {
done = true;
int pids[] = getStorageUsers(path);
if (pids == null || pids.length == 0) {
done = true;
} else {
// Kill processes holding references first
ActivityManagerService ams = (ActivityManagerService)
ServiceManager.getService("activity");
// Eliminate system process here?
boolean ret = ams.killPidsForMemory(pids);
if (ret) {
// Confirm if file references have been freed.
pids = getStorageUsers(path);
if (pids == null || pids.length == 0) {
done = true;
}
}
}
}
}
if (done) {
mForceUnmounts.remove(0);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
ucb));
} else {
if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
Log.i(TAG, "Cannot unmount inspite of " +
MAX_UNMOUNT_RETRIES + " to unmount media");
// Send final broadcast indicating failure to unmount.
if (done) {
sizeArr[sizeArrN++] = i;
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
ucb));
} else {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
ucb.retries++),
RETRY_UNMOUNT_DELAY);
if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
Log.i(TAG, "Cannot unmount inspite of " +
MAX_UNMOUNT_RETRIES + " to unmount media");
// Send final broadcast indicating failure to unmount.
} else {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
ucb.retries++),
RETRY_UNMOUNT_DELAY);
}
}
}
// Remove already processed elements from list.
for (int i = (sizeArrN-1); i >= 0; i--) {
mForceUnmounts.remove(sizeArr[i]);
}
break;
}
case H_UNMOUNT_MS : {
@@ -826,7 +868,7 @@ class MountService extends IMountService.Stub
}
}
public void shutdown() {
public void shutdown(final IMountShutdownObserver observer) {
validatePermission(android.Manifest.permission.SHUTDOWN);
Log.i(TAG, "Shutting down");
@@ -865,12 +907,9 @@ class MountService extends IMountService.Stub
}
if (state.equals(Environment.MEDIA_MOUNTED)) {
/*
* If the media is mounted, then gracefully unmount it.
*/
if (doUnmountVolume(path, true) != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to unmount media for shutdown");
}
// Post a unmount message.
ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
}
}