Merge "Apply timeout for powerdown event and reset state machine when bluez crashes"

This commit is contained in:
Matthew Xie
2011-09-08 17:16:50 -07:00
committed by Android (Google) Code Review
3 changed files with 77 additions and 41 deletions

View File

@@ -109,6 +109,8 @@ final class BluetoothAdapterStateMachine extends StateMachine {
private static final int DEVICES_DISCONNECT_TIMEOUT = 104; private static final int DEVICES_DISCONNECT_TIMEOUT = 104;
// Prepare Bluetooth timeout happens // Prepare Bluetooth timeout happens
private static final int PREPARE_BLUETOOTH_TIMEOUT = 105; private static final int PREPARE_BLUETOOTH_TIMEOUT = 105;
// Bluetooth Powerdown timeout happens
private static final int POWER_DOWN_TIMEOUT = 106;
private Context mContext; private Context mContext;
private BluetoothService mBluetoothService; private BluetoothService mBluetoothService;
@@ -129,6 +131,8 @@ final class BluetoothAdapterStateMachine extends StateMachine {
private static final int PREPARE_BLUETOOTH_TIMEOUT_TIME = 10000; private static final int PREPARE_BLUETOOTH_TIMEOUT_TIME = 10000;
private static final int POWER_DOWN_TIMEOUT_TIME = 5000;
BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService, BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService,
BluetoothAdapter bluetoothAdapter) { BluetoothAdapter bluetoothAdapter) {
super(TAG); super(TAG);
@@ -386,6 +390,11 @@ final class BluetoothAdapterStateMachine extends StateMachine {
break; break;
case USER_TURN_OFF: // ignore case USER_TURN_OFF: // ignore
break; break;
case POWER_STATE_CHANGED:
if ((Boolean) message.obj) {
recoverStateMachine(TURN_HOT, null);
}
break;
default: default:
return NOT_HANDLED; return NOT_HANDLED;
} }
@@ -420,14 +429,27 @@ final class BluetoothAdapterStateMachine extends StateMachine {
} }
break; break;
case POWER_STATE_CHANGED: case POWER_STATE_CHANGED:
removeMessages(POWER_DOWN_TIMEOUT);
if (!((Boolean) message.obj)) { if (!((Boolean) message.obj)) {
transitionTo(mHotOff); if (mPublicState == BluetoothAdapter.STATE_TURNING_OFF) {
finishSwitchingOff(); transitionTo(mHotOff);
finishSwitchingOff();
}
} else {
if (mPublicState != BluetoothAdapter.STATE_TURNING_ON) {
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
recoverStateMachine(TURN_HOT, null);
} else {
recoverStateMachine(TURN_COLD, null);
}
}
} }
break; break;
case ALL_DEVICES_DISCONNECTED: case ALL_DEVICES_DISCONNECTED:
removeMessages(DEVICES_DISCONNECT_TIMEOUT); removeMessages(DEVICES_DISCONNECT_TIMEOUT);
mBluetoothService.switchConnectable(false); mBluetoothService.switchConnectable(false);
sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
break; break;
case DEVICES_DISCONNECT_TIMEOUT: case DEVICES_DISCONNECT_TIMEOUT:
sendMessage(ALL_DEVICES_DISCONNECTED); sendMessage(ALL_DEVICES_DISCONNECTED);
@@ -439,6 +461,17 @@ final class BluetoothAdapterStateMachine extends StateMachine {
deferMessage(obtainMessage(TURN_HOT)); deferMessage(obtainMessage(TURN_HOT));
} }
break; break;
case POWER_DOWN_TIMEOUT:
transitionTo(mHotOff);
finishSwitchingOff();
// reset the hardware for error recovery
Log.e(TAG, "Devices failed to power down, reseting...");
deferMessage(obtainMessage(TURN_COLD));
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
deferMessage(obtainMessage(TURN_HOT));
}
break;
case USER_TURN_ON: case USER_TURN_ON:
case AIRPLANE_MODE_OFF: case AIRPLANE_MODE_OFF:
case AIRPLANE_MODE_ON: case AIRPLANE_MODE_ON:
@@ -501,6 +534,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
DEVICES_DISCONNECT_TIMEOUT_TIME); DEVICES_DISCONNECT_TIMEOUT_TIME);
} else { } else {
mBluetoothService.switchConnectable(false); mBluetoothService.switchConnectable(false);
sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
} }
// we turn all the way to PowerOff with AIRPLANE_MODE_ON // we turn all the way to PowerOff with AIRPLANE_MODE_ON
@@ -520,6 +554,12 @@ final class BluetoothAdapterStateMachine extends StateMachine {
case PER_PROCESS_TURN_OFF: case PER_PROCESS_TURN_OFF:
perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
break; break;
case POWER_STATE_CHANGED:
if ((Boolean) message.obj) {
// reset the state machine and send it TURN_ON_CONTINUE message
recoverStateMachine(USER_TURN_ON, false);
}
break;
default: default:
return NOT_HANDLED; return NOT_HANDLED;
} }
@@ -540,7 +580,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
if (what == PER_PROCESS_TURN_ON) { if (what == PER_PROCESS_TURN_ON) {
isTurningOn = true; isTurningOn = true;
} else if (what == PER_PROCESS_TURN_OFF) { } else if (what == USER_TURN_OFF) {
isTurningOn = false; isTurningOn = false;
} else { } else {
Log.e(TAG, "enter PerProcessState: wrong msg: " + what); Log.e(TAG, "enter PerProcessState: wrong msg: " + what);
@@ -568,12 +608,31 @@ final class BluetoothAdapterStateMachine extends StateMachine {
} }
break; break;
case POWER_STATE_CHANGED: case POWER_STATE_CHANGED:
removeMessages(POWER_DOWN_TIMEOUT);
if (!((Boolean) message.obj)) { if (!((Boolean) message.obj)) {
transitionTo(mHotOff); transitionTo(mHotOff);
if (!mContext.getResources().getBoolean if (!mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
deferMessage(obtainMessage(TURN_COLD)); deferMessage(obtainMessage(TURN_COLD));
} }
} else {
if (!isTurningOn) {
recoverStateMachine(TURN_COLD, null);
for (IBluetoothStateChangeCallback c:
mBluetoothService.getApplicationStateChangeCallbacks()) {
perProcessCallback(false, c);
deferMessage(obtainMessage(PER_PROCESS_TURN_ON, c));
}
}
}
break;
case POWER_DOWN_TIMEOUT:
transitionTo(mHotOff);
Log.e(TAG, "Power-down timed out, resetting...");
deferMessage(obtainMessage(TURN_COLD));
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
deferMessage(obtainMessage(TURN_HOT));
} }
break; break;
case USER_TURN_ON: case USER_TURN_ON:
@@ -616,10 +675,12 @@ final class BluetoothAdapterStateMachine extends StateMachine {
perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) { if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
mBluetoothService.switchConnectable(false); mBluetoothService.switchConnectable(false);
sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
} }
break; break;
case AIRPLANE_MODE_ON: case AIRPLANE_MODE_ON:
mBluetoothService.switchConnectable(false); mBluetoothService.switchConnectable(false);
sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
allProcessesCallback(false); allProcessesCallback(false);
// we turn all the way to PowerOff with AIRPLANE_MODE_ON // we turn all the way to PowerOff with AIRPLANE_MODE_ON
deferMessage(obtainMessage(AIRPLANE_MODE_ON)); deferMessage(obtainMessage(AIRPLANE_MODE_ON));
@@ -699,6 +760,17 @@ final class BluetoothAdapterStateMachine extends StateMachine {
mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM); mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
} }
/**
* bluetoothd has crashed and recovered, the adapter state machine has to
* reset itself and try to return to previous state
*/
private void recoverStateMachine(int what, Object obj) {
Log.e(TAG, "Get unexpected power on event, reset with: " + what);
transitionTo(mHotOff);
deferMessage(obtainMessage(TURN_COLD));
deferMessage(obtainMessage(what, obj));
}
private void dump(PrintWriter pw) { private void dump(PrintWriter pw) {
IState currentState = getCurrentState(); IState currentState = getCurrentState();
if (currentState == mPowerOff) { if (currentState == mPowerOff) {

View File

@@ -59,9 +59,8 @@ class BluetoothEventLoop {
// from remote device when Android is in Suspend state. // from remote device when Android is in Suspend state.
private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mWakeLock;
private static final int EVENT_RESTART_BLUETOOTH = 1; private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 1;
private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2; private static final int EVENT_AGENT_CANCEL = 2;
private static final int EVENT_AGENT_CANCEL = 3;
private static final int CREATE_DEVICE_ALREADY_EXISTS = 1; private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
private static final int CREATE_DEVICE_SUCCESS = 0; private static final int CREATE_DEVICE_SUCCESS = 0;
@@ -75,9 +74,6 @@ class BluetoothEventLoop {
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
String address = null; String address = null;
switch (msg.what) { switch (msg.what) {
case EVENT_RESTART_BLUETOOTH:
mBluetoothService.restart();
break;
case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT: case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT:
address = (String)msg.obj; address = (String)msg.obj;
if (address != null) { if (address != null) {
@@ -375,9 +371,6 @@ class BluetoothEventLoop {
} else if (name.equals("Powered")) { } else if (name.equals("Powered")) {
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED, mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED,
propValues[1].equals("true") ? new Boolean(true) : new Boolean(false)); propValues[1].equals("true") ? new Boolean(true) : new Boolean(false));
// bluetoothd has restarted, re-read all our properties.
// Note: bluez only sends this property change when it restarts.
onRestartRequired();
} else if (name.equals("DiscoverableTimeout")) { } else if (name.equals("DiscoverableTimeout")) {
adapterProperties.setProperty(name, propValues[1]); adapterProperties.setProperty(name, propValues[1]);
} }
@@ -1033,14 +1026,6 @@ class BluetoothEventLoop {
mBluetoothService.onHealthDeviceChannelChanged(devicePath, channelPath, exists); mBluetoothService.onHealthDeviceChannelChanged(devicePath, channelPath, exists);
} }
private void onRestartRequired() {
if (mBluetoothService.isEnabled()) {
Log.e(TAG, "*** A serious error occurred (did bluetoothd crash?) - " +
"restarting Bluetooth ***");
mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
}
}
private static void log(String msg) { private static void log(String msg) {
Log.d(TAG, msg); Log.d(TAG, msg);
} }

View File

@@ -95,7 +95,6 @@ public class BluetoothService extends IBluetooth.Stub {
private boolean mIsAirplaneSensitive; private boolean mIsAirplaneSensitive;
private boolean mIsAirplaneToggleable; private boolean mIsAirplaneToggleable;
private BluetoothAdapterStateMachine mBluetoothState; private BluetoothAdapterStateMachine mBluetoothState;
private boolean mRestart = false; // need to call enable() after disable()
private int[] mAdapterSdpHandles; private int[] mAdapterSdpHandles;
private ParcelUuid[] mAdapterUuids; private ParcelUuid[] mAdapterUuids;
@@ -429,11 +428,6 @@ public class BluetoothService extends IBluetooth.Stub {
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
if (mRestart) {
mRestart = false;
enable();
}
} }
/** /**
@@ -456,10 +450,6 @@ public class BluetoothService extends IBluetooth.Stub {
// the adapter property could be changed before event loop is stoped, clear it again // the adapter property could be changed before event loop is stoped, clear it again
mAdapterProperties.clear(); mAdapterProperties.clear();
disableNative(); disableNative();
if (mRestart) {
mRestart = false;
enable();
}
} }
/** Bring up BT and persist BT on in settings */ /** Bring up BT and persist BT on in settings */
@@ -500,17 +490,6 @@ public class BluetoothService extends IBluetooth.Stub {
return true; return true;
} }
/** Forcibly restart Bluetooth if it is on */
/* package */ synchronized void restart() {
if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
return;
}
mRestart = true;
if (!disable(false)) {
mRestart = false;
}
}
private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {