[Android源碼分析]藍牙打開分析–苦盡甘來之再次回到jni之上

第三章,苦盡甘來之再次回到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的處理

 

[cpp]  

} 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)函數分析

 

[cpp]  

 /*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的關鍵條件,這個我們在藍牙的狀態機裡面有詳細分析,不過,我們不妨在這裡也再次分析一下:

 

[cpp] 

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的處理。

 

[cpp]  

    } 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中。

 

[cpp] 

} 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的分析  

 

[cpp]  

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的狀態:

 

 

 

[cpp]  

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的處理時一個函數,隻是多進入瞭一下這個函數:

 

[cpp] 

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

 

 

發佈留言