[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之類的,這裏等到具體分析到的時候我們再詳細的解釋吧。

 

至此,經過了很長一段時間(寫了有兩個月了吧)的分析,我們終於把藍牙打開涉及的方方面面都考慮到了。您還有什麼疑問麼?

 

若您覺得該文章對您有幫助,請在下面用鼠標輕輕按一下“頂”,哈哈~~·

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章