Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android源碼分析]藍牙打開分析--苦盡甘來之再次回到jni之上

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

編輯:關於Android編程

第三章,苦盡甘來之再次回到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之類的,這裡等到具體分析到的時候我們再詳細的解釋吧。    
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved