[Android源码分析]蓝牙打开分析--苦尽甘来之再次回到jni之上

第三章,苦尽甘来之再次回到jni之上

         经过了上面两章的分析,我们基本已经对一次的“下乡活动”了解清楚了,下面我们就要详细分析再次回到jni之上的一些操作了。再这之前,我们先来看看这次下乡活动从乡下都带来了什么?

         其实很少蛮清晰的,就是带回来了几个property changeevent,他们分别是UUIDspairable=falsepowered=falseclass discoverable=false。我们来看一下,他们对上层都有哪些影响。

         eventloop中对property change的处理函数是:

/*package*/ void onPropertyChanged(String[] propValues) {

         所以,我们要分析各个propertychange的影响分析这个函数就可以了。下面,我们来具体分析这些property change的影响:

1UUIDs的处理

  } else if (name.equals("Devices") || name.equals("UUIDs")) {
            String value = null;
            int len = Integer.valueOf(propValues[1]);
            if (len > 0) {
                StringBuilder str = new StringBuilder();
                for (int i = 2; i < propValues.length; i++) {
                    str.append(propValues[i]);
                    str.append(",");
                }
                value = str.toString();
            }
		//加入到property中,把UUIDs和对应的value保存
            adapterProperties.setProperty(name, value);
            if (name.equals("UUIDs")) {
				//若是uuid,这个函数是很重要的
                mBluetoothService.updateBluetoothState(value);
            }


 

1.2 mBluetoothService.updateBluetoothState(value)函数分析

 /*package*/ synchronized void updateBluetoothState(String uuids) {
        ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
	
//当uuid都被注册成功之后,就可以发送SERVICE_RECORD_LOADED的msg了
        if (mAdapterUuids != null &&
            BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
            mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);
        }
}


 

          所以,UUIDsproperty change的最终目的就是发送SERVICE_RECORD_LOADEDmsg,这个msg是从warmuphotoff的关键条件,这个我们在蓝牙的状态机里面有详细分析,不过,我们不妨在这里也再次分析一下:

 switch(message.what) {
                case SERVICE_RECORD_LOADED:
                    removeMessages(PREPARE_BLUETOOTH_TIMEOUT);
			//转换到hotoff的状态
                    transitionTo(mHotOff);
                    break;
	到了hotoff状态之后,我们需要继续处理在poweroff状态中传入的turnon continue的msg:
                case TURN_ON_CONTINUE:
				//这个就是设置powered为true
                    mBluetoothService.switchConnectable(true);
                    transitionTo(mSwitching);
                    break;
	//从注释来看,这里是用来设置connectable和pairable的,又要到jni层之下,不过我们直接去看吧,就没有必要再分开分析了。
  /*package*/ synchronized void switchConnectable(boolean on) {
        setAdapterPropertyBooleanNative("Powered", on ? 1 : 0);
}


 

1.3 bluezset propertypowered的处理

这个函数是处理很多property的不同的,所以,这里我们直接分析powered的处理。

	} else if (g_str_equal("Powered", property)) {
		gboolean powered;
	//得到参数,这里就是1了
		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
			return btd_error_invalid_args(msg);

		dbus_message_iter_get_basic(&sub, &powered);
//调用这个函数
		return set_powered(conn, msg, powered, data);
}

下面就来看一下set_powered都做了些什么:
static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
				gboolean powered, void *data)
{
	struct btd_adapter *adapter = data;
	uint8_t mode;
	int err;
	//就是先这个了
	if (powered) {
		//mode是off
		mode = get_mode(&adapter->bdaddr, "on");
//所以,这个地方是传入的false
		return set_discoverable(conn, msg, mode == MODE_DISCOVERABLE,
									data);
	}
……

	return NULL;
}
static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg,
				gboolean discoverable, void *data)
{
	struct btd_adapter *adapter = data;
	uint8_t mode;
	int err;
	//这里discoverable是0,所以mode connectable
	mode = discoverable ? MODE_DISCOVERABLE : MODE_CONNECTABLE;
	//adapter的mode是off
	if (mode == adapter->mode) {
		adapter->global_mode = mode;
		return dbus_message_new_method_return(msg);
	}
//这里adapter的mode是off,mode是iteconnectable
	err = set_mode(adapter, mode, msg);
	/* when called by discov_timeout_handler(), msg may be NULL, and cause dbus error */
	if (err < 0 && msg != NULL)
		return btd_error_failed(msg, strerror(-err));

	return NULL;
}
继续看
static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
			DBusMessage *msg)
{
	int err;
	const char *modestr;

	if (adapter->pending_mode != NULL)
		return -EALREADY;
	//我们是肯定up了,new mode为connectable
	if (!adapter->up && new_mode != MODE_OFF) {
		err = adapter_ops->set_powered(adapter->dev_id, TRUE);
		if (err < 0)
			return err;

		goto done;
	}

	if (adapter->up && new_mode == MODE_OFF) {
		err = adapter_ops->set_powered(adapter->dev_id, FALSE);
		if (err < 0)
			return err;

		adapter->off_requested = TRUE;

		goto done;
	}

	if (new_mode == adapter->mode)
		return 0;
	//new mode 是connectable,就是hciops中的set discoverable,同时因为discoverable是false,所以,就是page scan
	err = adapter_set_mode(adapter, new_mode);
done:
	//新的mode 是connectable
	modestr = mode2str(new_mode);
	//把它写入到config文件on mode中
	write_device_mode(&adapter->bdaddr, modestr);

	DBG("%s", modestr);

	if (msg != NULL) {
		struct session_req *req;
	//用来看是否需要回给jni层内容,这里必然有一个
		req = find_session_by_msg(adapter->mode_sessions, msg);
		if (req) {
			adapter->pending_mode = req;
			session_ref(req);
		} else
			/* Wait for mode change to reply */
			adapter->pending_mode = create_session(adapter,
					connection, msg, new_mode, NULL);
	} else
		/* Nothing to reply just write the new mode */
		adapter->mode = new_mode;

	return 0;
}


 

所以,这里其实说白了就是发送了一个write scan enablecmd,这个cmdevent我们在前文中都分析过了,会去read scan enable,然后通知上层pairableproperty change。这个我们在2中进行分析。

2. pairableproperty change的处理

同样的,property change的处理还是在eventloop中。

   } else if (name.equals("Pairable") || name.equals("Discoverable")) {
        	//设置property的值
            adapterProperties.setProperty(name, propValues[1]);

            if (name.equals("Discoverable")) {
                mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SCAN_MODE_CHANGED);
            }
			//得到对应的值
            String pairable = name.equals("Pairable") ? propValues[1] :
                adapterProperties.getProperty("Pairable");
            String discoverable = name.equals("Discoverable") ? propValues[1] :
                adapterProperties.getProperty("Discoverable");

            // This shouldn't happen, unless Adapter Properties are null.
            if (pairable == null || discoverable == null)
                return;
			//这里开始的时候discoverable是false,pairable是true
		            int mode = BluetoothService.bluezStringToScanMode(
                    pairable.equals("true"),
                    discoverable.equals("true"));
            if (mode >= 0) {
	//发送ACTION_SCAN_MODE_CHANGED的action
                Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
                intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                mContext.sendBroadcast(intent, BLUETOOTH_PERM);
            }


 

所以,对pairable这一property change的反应就是发送了ACTION_SCAN_MODE_CHANGEDaction。那么我们就来分析一下究竟有多少地方注册了这个actionreceiver

2.1 ACTION_SCAN_MODE_CHANGEDreceiver分析

         注册了这个action receiver的地方有:BluetoothDiscoverableEnabler

2.1.1 BluetoothDiscoverableEnabler中receiver的分析  

public void onReceive(Context context, Intent intent) {
            if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
                int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
                        BluetoothAdapter.ERROR);
//只要不是error,就需要handle mode的changed
                if (mode != BluetoothAdapter.ERROR) {
                    handleModeChanged(mode);
                }
            }
//mode changed的处理
    void handleModeChanged(int mode) {
	//打开的情况下,不会走到这,只有在后期设置可发现的时候,才会走到。UI上会显示一个可发现的倒计时吧。到了那时再具体分析,其实蛮简单的
        if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            mDiscoverable = true;
            updateCountdownSummary();
        } else {
			//这里的话,这里是false,这里就是显示两句话:
//1)假如没有配对设备,那么就是显示不让其他蓝牙设备检测到
//2)假如已经配对了设备,那么就是显示只让已配对的设备检测到
            mDiscoverable = false;
            setSummaryNotDiscoverable();
        }


 

3 poweredproperty change的处理

         同样的,对poweredproperty change的处理:

   } else if (name.equals("Powered")) {

//就是发送POWER_STATE_CHANGEDmsg。一看就知道是个state machinemsg,我们去看看吧            mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED,

                propValues[1].equals("true") ? new Boolean(true) : new Boolean(false));

 

此时,statemachine处于swtiching的状态:

 

               case POWER_STATE_CHANGED:

                    removeMessages(POWER_DOWN_TIMEOUT);

                            //这个if是false,我们是true,进else,我们在turnning on的状态,所以,没有什么好说的。

                    if (!((Boolean) message.obj)) {

                        if (mPublicState == BluetoothAdapter.STATE_TURNING_OFF) {

                            transitionTo(mHotOff);

                            finishSwitchingOff();

                            if (!mContext.getResources().getBoolean

                            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {

                                deferMessage(obtainMessage(TURN_COLD));

                            }

                        }

                    } 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;


所以,在这里,整个poweredchange并没有什么特别的处理。

 

4 discoverableproperty change的处理

这里discoveablefalse,和上面pairable的处理时一个函数,只是多进入了一下这个函数:

 if (name.equals("Discoverable")) {
                mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SCAN_MODE_CHANGED);
            }
至于上层ui的改变,因为discoverable是false,所以,还是不会做什么改变。所以就不去分析了,我们仍然只分析BluetoothAdapterStateMachine.SCAN_MODE_CHANGED这个action的处理。
	同样的,他仍然是一个adatperstatemachine的action,我们去swtiching的状态看看他的处理。
                case SCAN_MODE_CHANGED:
                    // This event matches mBluetoothService.switchConnectable action
                    if (mPublicState == BluetoothAdapter.STATE_TURNING_ON) {
                        // set pairable if it's not
				//假如pairable不是true,就去设置pairable,因为我们已经设置了,所以这就不会有什么了。
                        mBluetoothService.setPairable();
			//这个函数在蓝牙的状态机装换中已经分析过,不再详细分析。
                        mBluetoothService.initBluetoothAfterTurningOn();
			//转变到buetoothon的状态
                        transitionTo(mBluetoothOn);
		//广播BluetoothAdapter.ACTION_STATE_CHANGED,这次的值是STATE_ON,所以,我们还是有必要再次分析一下的。
                        broadcastState(BluetoothAdapter.STATE_ON);
                        // run bluetooth now that it's turned on
                        // Note runBluetooth should be called only in adapter STATE_ON
				//主要就是自动连接。其它也没有做什么特别的,见下面的简单分析
                        mBluetoothService.runBluetooth();
                    }
                    break;

    /*package*/ void runBluetooth() {
    //若是有可连接的设备,这里去进行自动连接。这个这里就不分析了
        autoConnect();

        // Log bluetooth on to battery stats.
        //告诉电池管理那边,蓝牙打开了
        long ident = Binder.clearCallingIdentity();
        try {
            mBatteryStats.noteBluetoothOn();
        } catch (RemoteException e) {
            Log.e(TAG, "", e);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
}


我们在2.1.1中已经对BluetoothAdapter.ACTION_STATE_CHANGED这个action进行了详细的分析。它主要就是把ui上的按钮高亮了,其它还有一写profile会随着这个进行初始化,比如opp之类的,这里等到具体分析到的时候我们再详细的解释吧。

 

至此,经过了很长一段时间(写了有两个月了吧)的分析,我们终于把蓝牙打开涉及的方方面面都考虑到了。您还有什么疑问么?

 

若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值