第三章,苦尽甘来之再次回到jni之上
经过了上面两章的分析,我们基本已经对一次的“下乡活动”了解清楚了,下面我们就要详细分析再次回到jni之上的一些操作了。再这之前,我们先来看看这次下乡活动从乡下都带来了什么?
其实很少蛮清晰的,就是带回来了几个property change的event,他们分别是UUIDs,pairable=false,powered=false,class, discoverable=false。我们来看一下,他们对上层都有哪些影响。
eventloop中对property change的处理函数是:
/*package*/ void onPropertyChanged(String[] propValues) {
所以,我们要分析各个propertychange的影响分析这个函数就可以了。下面,我们来具体分析这些property change的影响:
1、UUIDs的处理
} 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);
}
}
所以,UUIDs的property change的最终目的就是发送SERVICE_RECORD_LOADED的msg,这个msg是从warmup到hotoff的关键条件,这个我们在蓝牙的状态机里面有详细分析,不过,我们不妨在这里也再次分析一下:
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 bluez中set property的powered的处理
这个函数是处理很多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 enable的cmd,这个cmd的event我们在前文中都分析过了,会去read scan enable,然后通知上层pairable的property change。这个我们在2中进行分析。
2. 对pairable的property 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_CHANGED的action。那么我们就来分析一下究竟有多少地方注册了这个action的receiver。
2.1 ACTION_SCAN_MODE_CHANGED的receiver分析
注册了这个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 powered的property change的处理
同样的,对powered的property change的处理:
} else if (name.equals("Powered")) {
//就是发送POWER_STATE_CHANGED的msg。一看就知道是个state machine的msg,我们去看看吧 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;
所以,在这里,整个powered的change并没有什么特别的处理。
4、 discoverable的property change的处理
这里discoveable是false,和上面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之类的,这里等到具体分析到的时候我们再详细的解释吧。
至此,经过了很长一段时间(写了有两个月了吧)的分析,我们终于把蓝牙打开涉及的方方面面都考虑到了。您还有什么疑问么?
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·