AdapterState.java revision f36540ab3e5e2e133aae8d1d9e7301fb37349314
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.bluetooth.btservice; 18 19import android.bluetooth.BluetoothAdapter; 20import android.os.Message; 21import android.os.UserManager; 22import android.util.Log; 23 24import com.android.internal.util.State; 25import com.android.internal.util.StateMachine; 26 27/** 28 * This state machine handles Bluetooth Adapter State. 29 * States: 30 * {@link OnState} : Bluetooth is on at this state 31 * {@link OffState}: Bluetooth is off at this state. This is the initial 32 * state. 33 * {@link PendingCommandState} : An enable / disable operation is pending. 34 * TODO(BT): Add per process on state. 35 */ 36 37final class AdapterState extends StateMachine { 38 private static final boolean DBG = true; 39 private static final boolean VDBG = true; 40 private static final String TAG = "BluetoothAdapterState"; 41 42 static final int BLE_TURN_ON = 0; 43 static final int USER_TURN_ON = 1; 44 static final int BREDR_STARTED=2; 45 static final int ENABLED_READY = 3; 46 static final int BLE_STARTED=4; 47 48 static final int USER_TURN_OFF = 20; 49 static final int BEGIN_DISABLE = 21; 50 static final int ALL_DEVICES_DISCONNECTED = 22; 51 static final int BLE_TURN_OFF = 23; 52 53 static final int DISABLED = 24; 54 static final int BLE_STOPPED=25; 55 static final int BREDR_STOPPED = 26; 56 57 static final int BREDR_START_TIMEOUT = 100; 58 static final int ENABLE_TIMEOUT = 101; 59 static final int DISABLE_TIMEOUT = 103; 60 static final int BLE_STOP_TIMEOUT = 104; 61 static final int SET_SCAN_MODE_TIMEOUT = 105; 62 static final int BLE_START_TIMEOUT = 106; 63 static final int BREDR_STOP_TIMEOUT = 107; 64 65 static final int USER_TURN_OFF_DELAY_MS=500; 66 67 //TODO: tune me 68 private static final int ENABLE_TIMEOUT_DELAY = 12000; 69 private static final int DISABLE_TIMEOUT_DELAY = 8000; 70 private static final int BREDR_START_TIMEOUT_DELAY = 4000; 71 //BLE_START_TIMEOUT can happen quickly as it just a start gattservice 72 private static final int BLE_START_TIMEOUT_DELAY = 2000; //To start GattService 73 private static final int BLE_STOP_TIMEOUT_DELAY = 2000; 74 //BREDR_STOP_TIMEOUT can < STOP_TIMEOUT 75 private static final int BREDR_STOP_TIMEOUT_DELAY = 4000; 76 private static final int PROPERTY_OP_DELAY =2000; 77 private AdapterService mAdapterService; 78 private AdapterProperties mAdapterProperties; 79 private PendingCommandState mPendingCommandState = new PendingCommandState(); 80 private OnState mOnState = new OnState(); 81 private OffState mOffState = new OffState(); 82 private BleOnState mBleOnState = new BleOnState(); 83 84 public boolean isTurningOn() { 85 return mPendingCommandState.isTurningOn(); 86 } 87 88 public boolean isBleTurningOn() { 89 return mPendingCommandState.isBleTurningOn(); 90 } 91 92 public boolean isBleTurningOff() { 93 return mPendingCommandState.isBleTurningOff(); 94 } 95 96 public boolean isTurningOff() { 97 return mPendingCommandState.isTurningOff(); 98 } 99 100 private AdapterState(AdapterService service, AdapterProperties adapterProperties) { 101 super("BluetoothAdapterState:"); 102 addState(mOnState); 103 addState(mBleOnState); 104 addState(mOffState); 105 addState(mPendingCommandState); 106 mAdapterService = service; 107 mAdapterProperties = adapterProperties; 108 setInitialState(mOffState); 109 } 110 111 public static AdapterState make(AdapterService service, AdapterProperties adapterProperties) { 112 Log.d(TAG, "make() - Creating AdapterState"); 113 AdapterState as = new AdapterState(service, adapterProperties); 114 as.start(); 115 return as; 116 } 117 118 public void doQuit() { 119 quitNow(); 120 } 121 122 private void cleanup() { 123 if(mAdapterProperties != null) 124 mAdapterProperties = null; 125 if(mAdapterService != null) 126 mAdapterService = null; 127 } 128 129 @Override 130 protected void onQuitting() { 131 cleanup(); 132 } 133 134 private class OffState extends State { 135 @Override 136 public void enter() { 137 infoLog("Entering OffState"); 138 } 139 140 @Override 141 public boolean processMessage(Message msg) { 142 AdapterService adapterService = mAdapterService; 143 if (adapterService == null) { 144 errorLog("Received message in OffState after cleanup: " + msg.what); 145 return false; 146 } 147 148 debugLog("Current state: OFF, message: " + msg.what); 149 150 switch(msg.what) { 151 case BLE_TURN_ON: 152 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON); 153 mPendingCommandState.setBleTurningOn(true); 154 transitionTo(mPendingCommandState); 155 sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY); 156 adapterService.BleOnProcessStart(); 157 break; 158 159 case USER_TURN_OFF: 160 //TODO: Handle case of service started and stopped without enable 161 break; 162 163 default: 164 return false; 165 } 166 return true; 167 } 168 } 169 170 private class BleOnState extends State { 171 @Override 172 public void enter() { 173 infoLog("Entering BleOnState"); 174 } 175 176 @Override 177 public boolean processMessage(Message msg) { 178 179 AdapterService adapterService = mAdapterService; 180 AdapterProperties adapterProperties = mAdapterProperties; 181 if ((adapterService == null) || (adapterProperties == null)) { 182 errorLog("Received message in BleOnState after cleanup: " + msg.what); 183 return false; 184 } 185 186 debugLog("Current state: BLE ON, message: " + msg.what); 187 188 switch(msg.what) { 189 case USER_TURN_ON: 190 notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON); 191 mPendingCommandState.setTurningOn(true); 192 transitionTo(mPendingCommandState); 193 sendMessageDelayed(BREDR_START_TIMEOUT, BREDR_START_TIMEOUT_DELAY); 194 adapterService.startCoreServices(); 195 break; 196 197 case USER_TURN_OFF: 198 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF); 199 mPendingCommandState.setBleTurningOff(true); 200 adapterProperties.onBleDisable(); 201 transitionTo(mPendingCommandState); 202 sendMessageDelayed(DISABLE_TIMEOUT, DISABLE_TIMEOUT_DELAY); 203 boolean ret = adapterService.disableNative(); 204 if (!ret) { 205 removeMessages(DISABLE_TIMEOUT); 206 errorLog("Error while calling disableNative"); 207 //FIXME: what about post enable services 208 mPendingCommandState.setBleTurningOff(false); 209 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 210 } 211 break; 212 213 default: 214 return false; 215 } 216 return true; 217 } 218 } 219 220 private class OnState extends State { 221 @Override 222 public void enter() { 223 infoLog("Entering OnState"); 224 225 AdapterService adapterService = mAdapterService; 226 if (adapterService == null) { 227 errorLog("Entered OnState after cleanup"); 228 return; 229 } 230 adapterService.updateUuids(); 231 } 232 233 @Override 234 public boolean processMessage(Message msg) { 235 AdapterProperties adapterProperties = mAdapterProperties; 236 if (adapterProperties == null) { 237 errorLog("Received message in OnState after cleanup: " + msg.what); 238 return false; 239 } 240 241 debugLog("Current state: ON, message: " + msg.what); 242 243 switch(msg.what) { 244 case BLE_TURN_OFF: 245 notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_OFF); 246 mPendingCommandState.setTurningOff(true); 247 transitionTo(mPendingCommandState); 248 249 // Invoke onBluetoothDisable which shall trigger a 250 // setScanMode to SCAN_MODE_NONE 251 Message m = obtainMessage(SET_SCAN_MODE_TIMEOUT); 252 sendMessageDelayed(m, PROPERTY_OP_DELAY); 253 adapterProperties.onBluetoothDisable(); 254 break; 255 256 case USER_TURN_ON: 257 break; 258 259 default: 260 return false; 261 } 262 return true; 263 } 264 } 265 266 private class PendingCommandState extends State { 267 private boolean mIsTurningOn; 268 private boolean mIsTurningOff; 269 private boolean mIsBleTurningOn; 270 private boolean mIsBleTurningOff; 271 272 public void enter() { 273 infoLog("Entering PendingCommandState"); 274 } 275 276 public void setTurningOn(boolean isTurningOn) { 277 mIsTurningOn = isTurningOn; 278 } 279 280 public boolean isTurningOn() { 281 return mIsTurningOn; 282 } 283 284 public void setTurningOff(boolean isTurningOff) { 285 mIsTurningOff = isTurningOff; 286 } 287 288 public boolean isTurningOff() { 289 return mIsTurningOff; 290 } 291 292 public void setBleTurningOn(boolean isBleTurningOn) { 293 mIsBleTurningOn = isBleTurningOn; 294 } 295 296 public boolean isBleTurningOn() { 297 return mIsBleTurningOn; 298 } 299 300 public void setBleTurningOff(boolean isBleTurningOff) { 301 mIsBleTurningOff = isBleTurningOff; 302 } 303 304 public boolean isBleTurningOff() { 305 return mIsBleTurningOff; 306 } 307 308 @Override 309 public boolean processMessage(Message msg) { 310 311 /* Cache current states */ 312 /* TODO(eisenbach): Not sure why this is done at all. 313 * Seems like the mIs* variables should be protected, 314 * or really, removed. Which reminds me: This file needs 315 * a serious refactor...*/ 316 boolean isTurningOn = isTurningOn(); 317 boolean isTurningOff = isTurningOff(); 318 boolean isBleTurningOn = isBleTurningOn(); 319 boolean isBleTurningOff = isBleTurningOff(); 320 321 logTransientStates(); 322 323 AdapterService adapterService = mAdapterService; 324 AdapterProperties adapterProperties = mAdapterProperties; 325 if ((adapterService == null) || (adapterProperties == null)) { 326 errorLog("Received message in PendingCommandState after cleanup: " + msg.what); 327 return false; 328 } 329 330 debugLog("Current state: PENDING_COMMAND, message: " + msg.what); 331 332 switch (msg.what) { 333 case USER_TURN_ON: 334 if (isBleTurningOff || isTurningOff) { //TODO:do we need to send it after ble turn off also?? 335 infoLog("Deferring USER_TURN_ON request..."); 336 deferMessage(msg); 337 } 338 break; 339 340 case USER_TURN_OFF: 341 if (isTurningOn || isBleTurningOn) { 342 infoLog("Deferring USER_TURN_OFF request..."); 343 deferMessage(msg); 344 } 345 break; 346 347 case BLE_TURN_ON: 348 if (isTurningOff || isBleTurningOff) { 349 infoLog("Deferring BLE_TURN_ON request..."); 350 deferMessage(msg); 351 } 352 break; 353 354 case BLE_TURN_OFF: 355 if (isTurningOn || isBleTurningOn) { 356 infoLog("Deferring BLE_TURN_OFF request..."); 357 deferMessage(msg); 358 } 359 break; 360 361 case BLE_STARTED: 362 //Remove start timeout 363 removeMessages(BLE_START_TIMEOUT); 364 365 //Enable 366 boolean isGuest = UserManager.get(mAdapterService).isGuestUser(); 367 if (!adapterService.enableNative(isGuest)) { 368 errorLog("Error while turning Bluetooth on"); 369 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 370 transitionTo(mOffState); 371 } else { 372 sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY); 373 } 374 break; 375 376 case BREDR_STARTED: 377 //Remove start timeout 378 removeMessages(BREDR_START_TIMEOUT); 379 adapterProperties.onBluetoothReady(); 380 mPendingCommandState.setTurningOn(false); 381 transitionTo(mOnState); 382 notifyAdapterStateChange(BluetoothAdapter.STATE_ON); 383 break; 384 385 case ENABLED_READY: 386 removeMessages(ENABLE_TIMEOUT); 387 mPendingCommandState.setBleTurningOn(false); 388 transitionTo(mBleOnState); 389 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 390 break; 391 392 case SET_SCAN_MODE_TIMEOUT: 393 warningLog("Timeout while setting scan mode. Continuing with disable..."); 394 //Fall through 395 case BEGIN_DISABLE: 396 removeMessages(SET_SCAN_MODE_TIMEOUT); 397 sendMessageDelayed(BREDR_STOP_TIMEOUT, BREDR_STOP_TIMEOUT_DELAY); 398 adapterService.stopProfileServices(); 399 break; 400 401 case DISABLED: 402 if (isTurningOn) { 403 removeMessages(ENABLE_TIMEOUT); 404 errorLog("Error enabling Bluetooth - hardware init failed?"); 405 mPendingCommandState.setTurningOn(false); 406 transitionTo(mOffState); 407 adapterService.stopProfileServices(); 408 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 409 break; 410 } 411 removeMessages(DISABLE_TIMEOUT); 412 sendMessageDelayed(BLE_STOP_TIMEOUT, BLE_STOP_TIMEOUT_DELAY); 413 if (adapterService.stopGattProfileService()) { 414 debugLog("Stopping Gatt profile services that were post enabled"); 415 break; 416 } 417 //Fall through if no services or services already stopped 418 case BLE_STOPPED: 419 removeMessages(BLE_STOP_TIMEOUT); 420 setBleTurningOff(false); 421 transitionTo(mOffState); 422 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 423 break; 424 425 case BREDR_STOPPED: 426 removeMessages(BREDR_STOP_TIMEOUT); 427 setTurningOff(false); 428 transitionTo(mBleOnState); 429 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 430 break; 431 432 case BLE_START_TIMEOUT: 433 errorLog("Error enabling Bluetooth (BLE start timeout)"); 434 mPendingCommandState.setBleTurningOn(false); 435 transitionTo(mOffState); 436 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 437 break; 438 439 case BREDR_START_TIMEOUT: 440 errorLog("Error enabling Bluetooth (start timeout)"); 441 mPendingCommandState.setTurningOn(false); 442 adapterService.stopProfileServices(); 443 transitionTo(mBleOnState); 444 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 445 break; 446 447 case ENABLE_TIMEOUT: 448 errorLog("Error enabling Bluetooth (enable timeout)"); 449 mPendingCommandState.setBleTurningOn(false); 450 transitionTo(mOffState); 451 adapterService.stopProfileServices(); 452 adapterService.stopGattProfileService(); 453 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 454 break; 455 456 case BREDR_STOP_TIMEOUT: 457 errorLog("Error stopping Bluetooth profiles (stop timeout)"); 458 mPendingCommandState.setTurningOff(false); 459 transitionTo(mBleOnState); 460 notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); 461 break; 462 463 case BLE_STOP_TIMEOUT: 464 errorLog("Error stopping Bluetooth profiles (BLE stop timeout)"); 465 mPendingCommandState.setTurningOff(false); 466 transitionTo(mOffState); 467 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 468 break; 469 470 case DISABLE_TIMEOUT: 471 errorLog("Error disabling Bluetooth (disable timeout)"); 472 if (isTurningOn) 473 mPendingCommandState.setTurningOn(false); 474 adapterService.stopProfileServices(); 475 adapterService.stopGattProfileService(); 476 mPendingCommandState.setTurningOff(false); 477 setBleTurningOff(false); 478 transitionTo(mOffState); 479 notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); 480 break; 481 482 default: 483 return false; 484 } 485 return true; 486 } 487 488 private void logTransientStates() { 489 StringBuilder sb = new StringBuilder(); 490 sb.append("PendingCommand - transient state(s):"); 491 492 if (isTurningOn()) sb.append(" isTurningOn"); 493 if (isTurningOff()) sb.append(" isTurningOff"); 494 if (isBleTurningOn()) sb.append(" isBleTurningOn"); 495 if (isBleTurningOff()) sb.append(" isBleTurningOff"); 496 497 verboseLog(sb.toString()); 498 } 499 } 500 501 private void notifyAdapterStateChange(int newState) { 502 AdapterService adapterService = mAdapterService; 503 AdapterProperties adapterProperties = mAdapterProperties; 504 if ((adapterService == null) || (adapterProperties == null)) { 505 errorLog("notifyAdapterStateChange after cleanup:" + newState); 506 return; 507 } 508 509 int oldState = adapterProperties.getState(); 510 adapterProperties.setState(newState); 511 infoLog("Bluetooth adapter state changed: " + oldState + "-> " + newState); 512 adapterService.updateAdapterState(oldState, newState); 513 } 514 515 void stateChangeCallback(int status) { 516 if (status == AbstractionLayer.BT_STATE_OFF) { 517 sendMessage(DISABLED); 518 519 } else if (status == AbstractionLayer.BT_STATE_ON) { 520 // We should have got the property change for adapter and remote devices. 521 sendMessage(ENABLED_READY); 522 523 } else { 524 errorLog("Incorrect status in stateChangeCallback"); 525 } 526 } 527 528 private void infoLog(String msg) { 529 if (DBG) Log.i(TAG, msg); 530 } 531 532 private void debugLog(String msg) { 533 if (DBG) Log.d(TAG, msg); 534 } 535 536 private void warningLog(String msg) { 537 if (DBG) Log.w(TAG, msg); 538 } 539 540 private void verboseLog(String msg) { 541 if (VDBG) Log.v(TAG, msg); 542 } 543 544 private void errorLog(String msg) { 545 Log.e(TAG, msg); 546 } 547 548} 549