Android4.0中蓝牙适配器state machine(状态机)的分析

今天晓东和大家来一起看一下Android4.0中蓝牙适配器(Bluetooth Adapter)的状态机变化的过程。首先,我们需要了解一下,蓝牙适配器究竟有哪些状态,从代码可以清晰地看到(frameworks/base/core/java/android/server/bluetoothadapterstatemachine.java):

[java] view plain copy
  1. BluetoothAdapterStateMachine(Contextcontext,BluetoothServicebluetoothService,
  2. BluetoothAdapterbluetoothAdapter){
  3. ……
  4. //bluetoothadapter的六个状态
  5. mBluetoothOn=newBluetoothOn();
  6. mSwitching=newSwitching();
  7. mHotOff=newHotOff();
  8. mWarmUp=newWarmUp();
  9. mPowerOff=newPowerOff();
  10. mPerProcessState=newPerProcessState();
  11. ……
  12. }


bluetooth adapter有六个状态,分别为:

1BluetoothOn:就是打开的状态。

2Switching:可以认为是正在打开的状态。

3HotOff:这个状态可以理解为一个预热状态,他是在上电之后进行了一系列硬件初始化成功之后的状态,但是这种状态并不表现到ui上。但是从耗电的状态来看,他和2.3bluetooth on是一样的。

4WarmUp:可以理解为正在预热的状态,就是处于从断电到HotOff的状态。

5PowerOff:就是掉电的状态,也就是正在的关闭状态,这个时候bluetooth是没有耗电(准确说是耗电很少)。

6PerProcessState:他也是位于HotOffBluetoothOn之间的一个状态,和Switching的差别在于Swtiching是我们通过ui上去打开的“正在打开”的状态,而perprocess则是应用于一些临时使用蓝牙的application,这些application并不需要完整的蓝牙功能(比如说在蓝牙打开后的自动连接等),也不需要ui上去显示蓝牙的打开。所以,有这样一个过渡的状态,在changeBluetoothOn的时候并不会发出类似state_onbroadcaset。当然,这个状态的使用场合并不是很多,大家了解一下就可以了。

各个状态之间的变化如下图所示。

从图中可以看出,这六个状态中有3个状态是bluetooth有可能长期处于的状态,也就是非中间状态,他们是BluetoothOnHotOff以及PowerOff。还有3个状态是中间状态,分别是SwitchingWarmUp以及PerProcessState

从代码来看,在最开始会处于PowerOff的状态,如下:

[java] view plain copy
  1. BluetoothAdapterStateMachine(Contextcontext,BluetoothServicebluetoothService,
  2. BluetoothAdapterbluetoothAdapter){
  3. ……
  4. setInitialState(mPowerOff);//初始化为PowerOff的状态
  5. mPublicState=BluetoothAdapter.STATE_OFF;
  6. }

因此,我们首先从PowerOff状态出发来分析:

[java] view plain copy
  1. privateclassPowerOffextendsState{
  2. @Override
  3. publicvoidenter(){
  4. if(DBG)log("EnterPowerOff:"+getCurrentMessage().what);
  5. }
  6. @Override
  7. publicbooleanprocessMessage(Messagemessage){
  8. log("PowerOffprocessmessage:"+message.what);
  9. booleanretValue=HANDLED;
  10. switch(message.what){
  11. //收到USER_TURN_ON的消息,一般而言,这个是用户在ui上点打开蓝牙会出现在这里。在bluetoothquickswitch关闭的情况下,这个消息是蓝牙真正打开的第一步。当然,若是bluetoothquickswitch打开了,是不会在这个状态收到这个消息的(除非出现了问题)
  12. caseUSER_TURN_ON:
  13. //startsturningonBTmodule,broadcastthisout
  14. //广播STATE_TURNING_ON的消息,可以做ui上显示等的处理
  15. broadcastState(BluetoothAdapter.STATE_TURNING_ON);
  16. //change到WarmUp的状态
  17. transitionTo(mWarmUp);
  18. //对蓝牙的初始化,我们暂时不管,后面我们有专门的文章来解释
  19. if(prepareBluetooth()){
  20. //thisisuserrequest,savethesetting
  21. if((Boolean)message.obj){
  22. persistSwitchSetting(true);
  23. }
  24. //WewillcontinueturntheBTonallthewaytotheBluetoothOnstate
  25. //若是成功,我们会发TURN_ON_CONTINUE的msg,
  26. //需要注意的是这个msg,是在warmup状态中进行处理的哦
  27. deferMessage(obtainMessage(TURN_ON_CONTINUE));
  28. }else{
  29. //当然,若是失败,我们需要回到poweroff的状态
  30. Log.e(TAG,"failedtopreparebluetooth,abortturningon");
  31. transitionTo(mPowerOff);
  32. broadcastState(BluetoothAdapter.STATE_OFF);
  33. }
  34. break;
  35. //这个case,TURN_HOT就是在bluetoothquickswitch打开的情况下,我们接收到这个msg,使得在开机之后,即使蓝牙没有打开,我们也会去做蓝牙controller初始化相关的操作,在上一篇文章中的《Android启动之bluetooth》中我们在initAfterRegistration中就有这个msg的发出,同样是根据quickswitch来判断的。
  36. caseTURN_HOT:
  37. //这里我们会发现,我们还是去初始化蓝牙相关的操作,不同的是,我们没有任何的广播消息发出,所以别的recever包括ui都是不知道我们偷偷做这个操作的。
  38. if(prepareBluetooth()){
  39. transitionTo(mWarmUp);//在初始化成功后,我们仍然会change到WarmUp
  40. }
  41. break;
  42. //对于飞行模式,我们并不陌生,它主要控制电话,wifi,和蓝牙,所以,毫无疑问,我们需要对飞行模式做一些处理。其实用脚趾头想我们都知道做了些什么,若是打开飞行模式之前蓝牙是打开的,那么关闭飞行模式,我们仍然需要打开它。若是打开飞行模式之前蓝牙是关闭的,那么关闭飞行模式的时候,我们根据quickswitch的值来判断是否重新打开
  43. caseAIRPLANE_MODE_OFF:
  44. if(getBluetoothPersistedSetting()){
  45. //之前是打开的,和USER_TURN_ON的处理是相同的
  46. //startsturningonBTmodule,broadcastthisout
  47. broadcastState(BluetoothAdapter.STATE_TURNING_ON);
  48. transitionTo(mWarmUp);
  49. if(prepareBluetooth()){
  50. //WewillcontinueturntheBTonallthewaytotheBluetoothOnstate
  51. deferMessage(obtainMessage(TURN_ON_CONTINUE));
  52. transitionTo(mWarmUp);
  53. }else{
  54. Log.e(TAG,"failedtopreparebluetooth,abortturningon");
  55. transitionTo(mPowerOff);
  56. broadcastState(BluetoothAdapter.STATE_OFF);
  57. }
  58. //之前是关闭的,需要根据quickswitch的值来进行判断,看是否发送TURN_HOT的msg
  59. }elseif(mContext.getResources().getBoolean
  60. (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)){
  61. sendMessage(TURN_HOT);
  62. }
  63. break;
  64. //这个是上文所说的一些应用直接调用changeApplicationBluetoothStateapi之后会发出的msg,只会做蓝牙的打开操作,同样不会有任何的ui上的显示。
  65. casePER_PROCESS_TURN_ON:
  66. if(prepareBluetooth()){
  67. transitionTo(mWarmUp);
  68. }
  69. deferMessage(obtainMessage(PER_PROCESS_TURN_ON));
  70. break;
  71. //其它的msg都是无关紧要的,不加以分析了
  72. ……
  73. returnretValue;
  74. }

到这里,我们可以看到Poweroff状态下的msg分析就已经都完成了,比较关键的几个msgUSER_TURN_ON—UI上打开蓝牙的msgTURN_HOT—quick switch打开的时候,默认打开蓝牙的msgAIRPLANE_MODE_OFF—飞行模式关闭的msgok,下面我们去看一下warmup这个状态的处理。

[java] view plain copy
  1. privateclassWarmUpextendsState{
  2. @Override
  3. publicvoidenter(){
  4. if(DBG)log("EnterWarmUp:"+getCurrentMessage().what);
  5. }
  6. @Override
  7. publicbooleanprocessMessage(Messagemessage){
  8. log("WarmUpprocessmessage:"+message.what);
  9. booleanretValue=HANDLED;
  10. switch(message.what){
  11. //sdpok,则把刚刚preparebluetooth中启动的一个定时器(10s)remove掉,同时change到hotoff的状态
  12. caseSERVICE_RECORD_LOADED:
  13. removeMessages(PREPARE_BLUETOOTH_TIMEOUT);
  14. transitionTo(mHotOff);
  15. break;
  16. casePREPARE_BLUETOOTH_TIMEOUT:
  17. Log.e(TAG,"BluetoothadapterSDPfailedtoload");
  18. //若是tiemout的话,我们就只能change到poweroff状态了。
  19. shutoffBluetooth();
  20. transitionTo(mPowerOff);
  21. broadcastState(BluetoothAdapter.STATE_OFF);
  22. break;
  23. caseUSER_TURN_ON://handlethisatHotOffstate
  24. caseTURN_ON_CONTINUE://OnceinHotOffstate,continueturnbluetooth
  25. //ontotheBluetoothOnstate
  26. caseAIRPLANE_MODE_ON:
  27. caseAIRPLANE_MODE_OFF:
  28. casePER_PROCESS_TURN_ON:
  29. casePER_PROCESS_TURN_OFF:
  30. //收到以上这些消息都是直接defer就可以了,到下一个状态中去处理,再刚刚poweroff状态收到user_turn_on的时候,是发了TURN_ON_CONTINUE这个msg的,这个msg会在hotoff状态中继续起作用哦
  31. deferMessage(message);
  32. break;
  33. caseUSER_TURN_OFF:
  34. Log.w(TAG,"WarmUpreceived:"+message.what);
  35. break;
  36. default:
  37. returnNOT_HANDLED;
  38. }
  39. returnretValue;
  40. }
  41. }


总的来看,warmup状态并没有做什么特别的事情,就是检测了sdp是否ok,去除了preparetimeout,仅此而已。所以,继续看hotoff的状态。

hotoff状态比较神奇,他就是为quick swtich而生的。对蓝牙controller而言,他是一个打开的状态,对上层应用来说,他就是一个关闭的状态。

[java] view plain copy
  1. privateclassHotOffextendsState{
  2. @Override
  3. publicvoidenter(){
  4. if(DBG)log("EnterHotOff:"+getCurrentMessage().what);
  5. }
  6. @Override
  7. publicbooleanprocessMessage(Messagemessage){
  8. log("HotOffprocessmessage:"+message.what);
  9. booleanretValue=HANDLED;
  10. switch(message.what){
  11. //这里其实就是ui上打开蓝牙了,需要注意的是,这里是不是没有change到别的状态哦?
  12. //这是为什么呢?这个case之后没有break啊,没有break,懂了吧。。。
  13. caseUSER_TURN_ON:
  14. broadcastState(BluetoothAdapter.STATE_TURNING_ON);
  15. if((Boolean)message.obj){
  16. persistSwitchSetting(true);
  17. }
  18. //这是什么,这是上面传下来的哦,所以ui在hotoff的状态下发这个msg,这里会继续处理的哦
  19. caseTURN_ON_CONTINUE:
  20. //这里就是蓝牙从hotoff到turnon之间要做的一个事情就是设置为connectable
  21. mBluetoothService.switchConnectable(true);
  22. //到switching的状态。
  23. transitionTo(mSwitching);
  24. break;
  25. //这里有两个msg,一个是飞行模式开,一个turncold,都会真正地去关闭蓝牙。
  26. //所以无论quickswitch是开还是关,之后飞行模式开了,都是会真正去关闭蓝牙的。
  27. caseAIRPLANE_MODE_ON:
  28. caseTURN_COLD:
  29. shutoffBluetooth();
  30. transitionTo(mPowerOff);
  31. broadcastState(BluetoothAdapter.STATE_OFF);
  32. break;
  33. //同样的飞行模式的打开的处理
  34. caseAIRPLANE_MODE_OFF:
  35. if(getBluetoothPersistedSetting()){
  36. broadcastState(BluetoothAdapter.STATE_TURNING_ON);
  37. transitionTo(mSwitching);
  38. mBluetoothService.switchConnectable(true);
  39. }
  40. break;
  41. break;
  42. //这里,不会走到swtiching的状态,会到mPerProcessState的状态,上面有详细的介绍
  43. casePER_PROCESS_TURN_ON:
  44. transitionTo(mPerProcessState);
  45. //ResendthePER_PROCESS_TURN_ONmessagesothatthecallback
  46. //canbesentthrough.
  47. deferMessage(message);
  48. mBluetoothService.switchConnectable(true);
  49. break;
  50. casePER_PROCESS_TURN_OFF:
  51. perProcessCallback(false,(IBluetoothStateChangeCallback)message.obj);
  52. break;
  53. caseUSER_TURN_OFF://ignore
  54. break;
  55. casePOWER_STATE_CHANGED:
  56. if((Boolean)message.obj){
  57. recoverStateMachine(TURN_HOT,null);
  58. }
  59. break;
  60. default:
  61. returnNOT_HANDLED;
  62. }
  63. returnretValue;
  64. }
  65. }


从代码来看,hotoff的状态就是对上层ui上的一些操作进行了响应,以及兼容了no quick swtich下面的ui打开操作。它会changeswtiching的状态或者mPerProcessState的状态。我们来看看吧

[java] view plain copy
  1. privateclassSwitchingextendsState{
  2. @Override
  3. publicvoidenter(){
  4. if(DBG)log("EnterSwitching:"+getCurrentMessage().what);
  5. }
  6. @Override
  7. publicbooleanprocessMessage(Messagemessage){
  8. log("Switchingprocessmessage:"+message.what);
  9. booleanretValue=HANDLED;
  10. switch(message.what){
  11. //从注释可以清晰地看到,这个msg是我们上面调用BluetoothService.switchConnectable(true);这个函数的正确回应
  12. caseSCAN_MODE_CHANGED:
  13. //ThiseventmatchesmBluetoothService.switchConnectableaction
  14. if(mPublicState==BluetoothAdapter.STATE_TURNING_ON){
  15. //setpairableifit'snot
  16. //设为可配对
  17. mBluetoothService.setPairable();
  18. //初始化bluetooth
  19. mBluetoothService.initBluetoothAfterTurningOn();
  20. //正式change到bluetoothon的状态
  21. transitionTo(mBluetoothOn);
  22. broadcastState(BluetoothAdapter.STATE_ON);
  23. //runbluetoothnowthatit'sturnedon
  24. //NoterunBluetoothshouldbecalledonlyinadapterSTATE_ON
  25. //这个函数做的事情其实就是打开后的自动连接了。
  26. mBluetoothService.runBluetooth();
  27. }
  28. break;
  29. casePOWER_STATE_CHANGED:
  30. removeMessages(POWER_DOWN_TIMEOUT);
  31. //power可以理解为电压的关闭
  32. if(!((Boolean)message.obj)){
  33. if(mPublicState==BluetoothAdapter.STATE_TURNING_OFF){
  34. //就是关闭了,change到hotoff状态
  35. transitionTo(mHotOff);
  36. finishSwitchingOff();
  37. //若是quickswitch没有设置,则会change到poweroff的状态
  38. if(!mContext.getResources().getBoolean
  39. (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)){
  40. deferMessage(obtainMessage(TURN_COLD));
  41. }
  42. }
  43. }else{
  44. //在turningon就没有什么好做的,否则,就是看到poweroff还是hotoff了
  45. if(mPublicState!=BluetoothAdapter.STATE_TURNING_ON){
  46. if(mContext.getResources().getBoolean
  47. (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)){
  48. recoverStateMachine(TURN_HOT,null);
  49. }else{
  50. recoverStateMachine(TURN_COLD,null);
  51. }
  52. }
  53. }
  54. break;
  55. //所有的remotedevice都断开连接了,则我们会在5s后发送一个POWER_DOWN_TIMEOUT的msg,这个msg和下面几个msg都是从on->switching的过程中要处理的,可以见下面bluetooth_on的msg处理分析
  56. caseALL_DEVICES_DISCONNECTED:
  57. removeMessages(DEVICES_DISCONNECT_TIMEOUT);
  58. mBluetoothService.switchConnectable(false);
  59. sendMessageDelayed(POWER_DOWN_TIMEOUT,POWER_DOWN_TIMEOUT_TIME);
  60. break;
  61. //设备断开超时了,直接复位一下
  62. caseDEVICES_DISCONNECT_TIMEOUT:
  63. sendMessage(ALL_DEVICES_DISCONNECTED);
  64. //resetthehardwareforerrorrecovery
  65. Log.e(TAG,"Devicesfailedtodisconnect,reseting...");
  66. deferMessage(obtainMessage(TURN_COLD));
  67. if(mContext.getResources().getBoolean
  68. (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)){
  69. deferMessage(obtainMessage(TURN_HOT));
  70. }
  71. break;
  72. //powerdowntimeout,也是直接复位
  73. casePOWER_DOWN_TIMEOUT:
  74. transitionTo(mHotOff);
  75. finishSwitchingOff();
  76. //resetthehardwareforerrorrecovery
  77. Log.e(TAG,"Devicesfailedtopowerdown,reseting...");
  78. deferMessage(obtainMessage(TURN_COLD));
  79. if(mContext.getResources().getBoolean
  80. (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)){
  81. deferMessage(obtainMessage(TURN_HOT));
  82. }
  83. break;
  84. ……


从上面可以看到switching主要是等待BluetoothService.switchConnectable(true)的结果,若是ok,就会到turn on的状态了,进入到打开的模式。至于PerProcessState的状体和swtiching的状态比较类似,只是少了一些通知而已,大家自己去分析哦。下面我们继续看bluetooth on的状态。

[java] view plain copy
  1. privateclassBluetoothOnextendsState{
  2. @Override
  3. publicvoidenter(){
  4. if(DBG)log("EnterBluetoothOn:"+getCurrentMessage().what);
  5. }
  6. @Override
  7. publicbooleanprocessMessage(Messagemessage){
  8. log("BluetoothOnprocessmessage:"+message.what);
  9. booleanretValue=HANDLED;
  10. switch(message.what){
  11. //这个是off的操作,就是ui上的关闭了
  12. caseUSER_TURN_OFF:
  13. if((Boolean)message.obj){
  14. persistSwitchSetting(false);
  15. }
  16. if(mBluetoothService.isDiscovering()){
  17. mBluetoothService.cancelDiscovery();
  18. }
  19. if(!mBluetoothService.isApplicationStateChangeTrackerEmpty()){
  20. transitionTo(mPerProcessState);
  21. deferMessage(obtainMessage(TURN_HOT));
  22. break;
  23. }
  24. //同样要注意,这里没有break哦
  25. //$FALL-THROUGH$toAIRPLANE_MODE_ON
  26. //和飞行模式打开的操作
  27. caseAIRPLANE_MODE_ON:
  28. broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
  29. transitionTo(mSwitching);
  30. if(mBluetoothService.getAdapterConnectionState()!=
  31. BluetoothAdapter.STATE_DISCONNECTED){
  32. //需要把所有已经连接的设备都disconnect掉
  33. mBluetoothService.disconnectDevices();
  34. sendMessageDelayed(DEVICES_DISCONNECT_TIMEOUT,
  35. DEVICES_DISCONNECT_TIMEOUT_TIME);
  36. }else{
  37. //没有连接设备,直接powerdown
  38. mBluetoothService.switchConnectable(false);
  39. sendMessageDelayed(POWER_DOWN_TIMEOUT,POWER_DOWN_TIMEOUT_TIME);
  40. }
  41. //weturnallthewaytoPowerOffwithAIRPLANE_MODE_ON
  42. if(message.what==AIRPLANE_MODE_ON){
  43. //Weinformalltheperprocesscallbacks
  44. allProcessesCallback(false);
  45. deferMessage(obtainMessage(AIRPLANE_MODE_ON));
  46. }
  47. break;
  48. ……
  49. returnretValue;
  50. }
  51. }

所以,看起来bluetooth_on的处理也比较单纯,就是一些关闭的尾巴处理。

至此,bluetoothadapterstate machine就已经全部分析完成了,回顾一下,有六个状态,BluetoothOnSwitchingHotOffWarmUpPowerOffPerProcessState,他们之间可以相互转换,从而达到打开关闭蓝牙的目的。

修改记录1:原本的状态图中,hotoff到poweroff有一个箭头画反了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值