第三章,苦尽甘来之再次回到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之类的,这里等到具体分析到的时候我们再详细的解释吧。
至此,经过了很长一段时间(写了有两个月了吧)的分析,我们终于把蓝牙打开涉及的方方面面都考虑到了。您还有什么疑问么?
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·