android4.0藍牙使能的詳細解析 (轉載)

此博客是轉載過來的哦。。。java

給本身博客定幾個部分:android

(1)寫在前面的話:一些寫博客時的廢話。app

(2)內容簡介:把文章的主要內容或者核心部分做一個框架性的歸納,以方便你們閱讀。框架

(3)正文:這個不須要解釋了。less


寫在前面的話:這是csdn上的第一篇博客,但願本身可以堅持寫下去,也但願可以獲得你們的支持。本文可能會涉及大量的源碼註釋,在文字方面可能不夠盡如人意,但願真正想理解該過程的同窗們可以耐心看下去。ide

內容簡介:本文詳細分析了android4.0中藍牙使能的過程,相比較android2.3,4.0中的藍牙最大的差異在於UI上on/off的僞開關。在android4.0中加入了adapter的狀態機。所謂的狀態機就相似於狀態轉換圖,在一個狀態收到某個特定的命令會變成另一個狀態,不一樣的命令能夠跳轉到不一樣的狀態(固然也有可能到同一狀態)。adapter的初始狀態爲poweroff,在android系統啓動的時候會進入warmup狀態,同時會進行UUID的add,該操做會引發propertychanged的UUID signal,該signal會使得狀態從warmup變換到hotoff狀態。所以在UI端off時其實adapter已經處於hotoff狀態而不是poweroff狀態。這一點是很關鍵的。在正文中,我會從假如我不知道這些開始來描繪整個使能的過程。函數

正文:oop

毫無疑問,bluetooth的打開是在Settings中進行的操做。所以,冤有頭,債有主,咱們來到了Settings.java中,果真發現了相關的代碼以下:測試

mBluetoothEnabler =new BluetoothEnabler(context, new Switch(context));ui

因而,咱們得以進入真正的藍牙操做的殿堂,好好進去看看吧。

 

1BluetoothEnabler的構造函數

 

    public BluetoothEnabler(Context context,Switch switch_) {

        mContext = context;

        mSwitch = switch_;

//很簡單了,去調用一個LocalBluetoothManager類的getInstance,其實會構造該類的

        LocalBluetoothManager manager =LocalBluetoothManager.getInstance(context);

        if (manager == null) {

            // Bluetooth is not supported

            mLocalAdapter = null;

            mSwitch.setEnabled(false);

        } else {

//構形成功後,經過manager獲得bluetoothadapter

            mLocalAdapter =manager.getBluetoothAdapter();

        }

//同時新建一個intent,用於接收ACTION_STATE_CHANGED

        mIntentFilter = newIntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

    }

 

2LocalBluetoothManager類的getInstance


    public static synchronizedLocalBluetoothManager getInstance(Context context) {

        if (sInstance == null) {

//2.1一樣的,這個會去調用LocalBluetoothAdaptergetInstance,也會構造該類

            LocalBluetoothAdapter adapter =LocalBluetoothAdapter.getInstance();

            if (adapter == null) {

                return null;

            }

            // This will be around as long asthis process is

            Context appContext =context.getApplicationContext();

//2.2構造LocalBluetoothManager

            sInstance = newLocalBluetoothManager(adapter, appContext);

        }

 

        return sInstance;

    }

2.1LocalBluetoothAdaptergetInstance

 

    static synchronized LocalBluetoothAdaptergetInstance() {

        if (sInstance == null) {

//2.1.1經過BluetoothAdapter獲得DefaultAdapter

            BluetoothAdapter adapter =BluetoothAdapter.getDefaultAdapter();

            if (adapter != null) {

//2.1.2如有該DefaultAdapter,則構造LocalBluetoothAdapter

                sInstance = newLocalBluetoothAdapter(adapter);

            }

        }

 

        return sInstance;

    }

 

2.1.1BluetoothAdapter獲得DefaultAdapter

 

    public static synchronized BluetoothAdaptergetDefaultAdapter() {

        if (sAdapter == null) {

            IBinder b =ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);

            if (b != null) {

                IBluetooth service =IBluetooth.Stub.asInterface(b);

                sAdapter = newBluetoothAdapter(service);

            }

        }

        return sAdapter;

    }

 

2.1.2構造LocalBluetoothAdapter

//其實就是 mAdapter的初始化而已

    privateLocalBluetoothAdapter(BluetoothAdapter adapter) {

        mAdapter = adapter;

    }

2.2構造LocalBluetoothManager

//管理本地藍牙類,用來在藍牙API子類上面再封裝一個接口

    privateLocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {

        mContext = context;

//mLocalAdapter初始化爲DefaultAdapter中獲得的值

mLocalAdapter= adapter;

//構造CachedBluetoothDeviceManager,用來管理遠程藍牙設備

        mCachedDeviceManager = newCachedBluetoothDeviceManager(context);

//2.2.1構建BluetoothEventManager,該類是用來管理廣播消息和回調函數的,即分發不一樣的消息去對UI進行處理

        mEventManager = newBluetoothEventManager(mLocalAdapter,

                mCachedDeviceManager, context);

//2.2.2該類提供對不一樣LocalBluetoothProfile object的訪問

        mProfileManager = newLocalBluetoothProfileManager(context,

                mLocalAdapter,mCachedDeviceManager, mEventManager);

    }

 

2.2.1構建BluetoothEventManager

 

    BluetoothEventManager(LocalBluetoothAdapteradapter,

            CachedBluetoothDeviceManagerdeviceManager, Context context) {

        mLocalAdapter = adapter;

        mDeviceManager = deviceManager;

//建立兩個IntentFilter

        mAdapterIntentFilter = newIntentFilter();

//這裏沒有對mProfileIntentFilter進行初始化,這個在LocalBluetoothProfileManageraddProfile中實現

        mProfileIntentFilter = newIntentFilter();

//建立一個HandlerHash

        mHandlerMap = new HashMap<String,Handler>();

        mContext = context;

 

//註冊對adapterDevice的幾個廣播消息的處理回調函數

//add actionmAdapterIntentFilter

        // Bluetooth on/off broadcasts

       addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, newAdapterStateChangedHandler());

 

        // Discovery broadcasts

       addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, newScanningStateChangedHandler(true));

       addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, newScanningStateChangedHandler(false));

       addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());

       addHandler(BluetoothDevice.ACTION_DISAPPEARED, newDeviceDisappearedHandler());

       addHandler(BluetoothDevice.ACTION_NAME_CHANGED, newNameChangedHandler());

 

        // Pairing broadcasts

       addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, newBondStateChangedHandler());

       addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, newPairingCancelHandler());

 

        // Fine-grained state broadcasts

       addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, newClassChangedHandler());

        addHandler(BluetoothDevice.ACTION_UUID,new UuidChangedHandler());

 

        // Dock event broadcasts

        addHandler(Intent.ACTION_DOCK_EVENT,new DockEventHandler());

//mAdapterIntentFilter的接收處理函數

       mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);

    }

 

2.2.2構造LocalBluetoothProfileManager

 

    LocalBluetoothProfileManager(Contextcontext,

            LocalBluetoothAdapter adapter,

            CachedBluetoothDeviceManagerdeviceManager,

            BluetoothEventManager eventManager){

        mContext = context;

 

//各個類之間進行關聯

        mLocalAdapter = adapter;

        mDeviceManager = deviceManager;

        mEventManager = eventManager;

        // pass this reference to adapter andevent manager (circular dependency)

        mLocalAdapter.setProfileManager(this);

        mEventManager.setProfileManager(this);

 

        ParcelUuid[] uuids =adapter.getUuids();

 

        // uuids may be null if Bluetooth isturned off

        if (uuids != null) {

//假如已經有了uuid,根據uuidaddnew對應的profile,只針對A2DP,HFP,HSP,OPP四個profileHIDPAN在下面,每次都add

            updateLocalProfiles(uuids);

        }

 

        // Always add HID and PAN profiles

//加入HIDPAN兩個profile

        mHidProfile = new HidProfile(context,mLocalAdapter);

        addProfile(mHidProfile,HidProfile.NAME,

               BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);

 

        mPanProfile = new PanProfile(context);

        addPanProfile(mPanProfile,PanProfile.NAME,

               BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);

 

        Log.d(TAG,"LocalBluetoothProfileManager construction complete");

    }

 

好吧,其實咱們被騙了,剛剛只是一個路引,不是真正的操做,真正的操做向來都是從你滑動界面那個on/off鍵開始的,所以咱們決定把這個鍵的處理給揪出來。在Settings界面上一共就只有兩個on/off鍵,一個是wifi,另外一個就是藍牙了,咱們從這個代碼入手:

                case HEADER_TYPE_SWITCH:

//其實寫這個代碼的人也比較心虛,假如switch多一點,下面就要重寫了

                    // Would need a differenttreatment if the main menu had more switches

                    if (header.id ==R.id.wifi_settings) {

                       mWifiEnabler.setSwitch(holder.switch_);

                    } else {

//這個就是處理了,上面的路引沒有白作啊

                       mBluetoothEnabler.setSwitch(holder.switch_);

                    }

 

3mBluetoothEnabler.setSwitch分析

 

    public void setSwitch(Switch switch_) {

//如果和上次相同,則不作任何事情,能夠理解,代碼也懶嘛

        if (mSwitch == switch_) return;

//把上次的switchchangelistener清空

       mSwitch.setOnCheckedChangeListener(null);

        mSwitch = switch_;

//重設此次的switchchangelistener

       mSwitch.setOnCheckedChangeListener(this);

 

        int bluetoothState =BluetoothAdapter.STATE_OFF;

//獲取getBluetoothState,這個過程也會同步一下state,防止改變

        if (mLocalAdapter != null)bluetoothState = mLocalAdapter.getBluetoothState();

//根據狀態設置一下兩個標誌位

        boolean isOn = bluetoothState ==BluetoothAdapter.STATE_ON;

        boolean isOff = bluetoothState ==BluetoothAdapter.STATE_OFF;

//設置checked的狀態位。注意,假如這裏狀態發生了改變,則會調用this.onCheckedChanged來進行處理

        mSwitch.setChecked(isOn);

        if(WirelessSettings.isRadioAllowed(mContext, Settings.System.RADIO_BLUETOOTH)) {

//bluetooth或者不是airplane,則該switch不變灰,不然,灰的。

            mSwitch.setEnabled(isOn || isOff);

        } else {

            mSwitch.setEnabled(false);

        }

    }

 

4onCheckedChanged

switch狀態發生改變後,會調用這個地方的回調函數進行處理。

 

    public void onCheckedChanged(CompoundButtonbuttonView, boolean isChecked) {

        // Show toast message if Bluetooth isnot allowed in airplane mode

//如果打開的話,就須要檢查一下是否allow Bluetoothradioairplanecheck

        if (isChecked &&

               !WirelessSettings.isRadioAllowed(mContext,Settings.System.RADIO_BLUETOOTH)) {

            Toast.makeText(mContext,R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();

            // Reset switch to off

//如果不對的話,resetoff

            buttonView.setChecked(false);

        }

 

        if (mLocalAdapter != null) {

//4.1設置scanmode,放心,它會判斷state的,不是STATE_ON,會直接返回false

           mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);

//4.2使能或不使能Bluetooth

           mLocalAdapter.setBluetoothEnabled(isChecked);

        }

//過程當中仍是會反灰,直到setBluetoothEnabled的結果返回會改變switch的狀態

        mSwitch.setEnabled(false);

    }

 

4.1設置scanmod

 

會調用adapter中的setScanMode,直接去看就能夠了,事實上就是設置了兩個property標誌,沒什麼

 

    public boolean setScanMode(int mode) {

//這裏把這個代碼寫出來就是證實一下,STATE_ON纔會真正作下去,不然免談

        if (getState() != STATE_ON) returnfalse;

//這裏會調用對應server中的setScanMode

        return setScanMode(mode, 120);

    }

 

    public synchronized boolean setScanMode(intmode, int duration) {

//這裏有個permission,好像和2.3中不同,注意一下     mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,

"NeedWRITE_SECURE_SETTINGS permission");

        boolean pairable;

        boolean discoverable;

 

        switch (mode) {

        case BluetoothAdapter.SCAN_MODE_NONE:

            pairable = false;

            discoverable = false;

            break;

        caseBluetoothAdapter.SCAN_MODE_CONNECTABLE:

//開始就是這裏了,可pairable,可是不可discoverable

            pairable = true;

            discoverable = false;

            break;

        caseBluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:

            pairable = true;

            discoverable = true;

            if (DBG) Log.d(TAG, "BTDiscoverable for " + duration + " seconds");

            break;

        default:

            Log.w(TAG, "Requested invalidscan mode " + mode);

            return false;

        }

 

//設置這兩個property標誌

       setPropertyBoolean("Discoverable", discoverable);

       setPropertyBoolean("Pairable", pairable);

        return true;

    }

 

4.2setBluetoothEnabled分析

 

    public void setBluetoothEnabled(booleanenabled) {

//根據enabled的標誌設置是enable仍是disable,在2.3中,這個地方就是bt_enable哦,這裏還不知道,咱們在第5步進行詳細的分析

        boolean success = enabled

                ? mAdapter.enable()

                : mAdapter.disable();

//成功了,設置對應的狀態位

        if (success) {

            setBluetoothStateInt(enabled

                ?BluetoothAdapter.STATE_TURNING_ON

                :BluetoothAdapter.STATE_TURNING_OFF);

        } else {

            if (Utils.V) {

                Log.v(TAG,"setBluetoothEnabled call, manager didn't return " +

                        "success forenabled: " + enabled);

            }

//同步一下設置的狀態

            syncBluetoothState();

        }

    }

}

 

5mAdapter.enable或者mAdapter.disable

 

就先分析enable吧,它會調用對應server端的enable(ture),咱們來看看源碼

 

    public synchronized boolean enable(booleansaveSetting) {

       mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,

                                               "Need BLUETOOTH_ADMIN permission");

 

        // Airplane mode can prevent Bluetoothradio from being turned on.

//檢查是不是飛行模式

        if (mIsAirplaneSensitive &&isAirplaneModeOn() && !mIsAirplaneToggleable) {

            return false;

        }

//5.1注意與2.3的不一樣,在2.3中,這裏會調用enablethread去調用nativebt_enable,而4.0沒有這麼作。沒事,咱們來分析4.0怎麼作的。

       mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON,saveSetting);

        return true;

    }

 

5.1mBluetoothState.sendMessage

 

簡單理解一下,mBluetoothStateBluetoothAdapterStateMachine類。所以,在分析的以前,簡單說一下,它其實就是相似一個狀態轉換圖,根據你所處於的狀態,而後再判斷收到的操做,進行不一樣的處理。根據構造函數中的setInitialState(mPowerOff);能夠知道初始狀態是PowerOff。可是從它給出的狀態機能夠看出,在PowerOff的狀態時,它是經過TURN_HOT/TURN_ON來改變到HotOff狀態的,而後纔會收到USER_TURN_ON,去該變到BluetootOn的狀態。所以,能夠確定的是咱們這裏的USER_TURN_ON不是它收到的第一個message所以咱們去糾結一下它是從哪裏開始改變PowerOff的狀態:extra1而後再來看這裏的處理吧:5.2

 

extra1mAdapter.enable以前的狀態機轉變

 

衆所周知,android在啓動以後會啓動一個serverThread的線程,經過這個線程會啓動一系列的服務。咱們的藍牙服務也是在這裏啓動的,android4.0其實在這個地方對狀態機進行了修改,咱們來看一下源碼:

該代碼位於framworks/base/services/java/com/android/server/systemserver.java

BluetoothServicebluetooth = null;

BluetoothA2dpServicebluetoothA2dp = null;

 

//模擬器上是不支持Bluetooth的,工廠測試模式也沒有Bluetooth(這個不瞭解)

            // Skip Bluetooth if we have anemulator kernel

            // TODO: Use a more reliable checkto see if this product should

            // support Bluetooth - see bug988521

            if(SystemProperties.get("ro.kernel.qemu").equals("1")) {

                Slog.i(TAG, "No BluetoohService (emulator)");

            } else if (factoryTest ==SystemServer.FACTORY_TEST_LOW_LEVEL) {

                Slog.i(TAG, "No BluetoothService (factory test)");

            } else {

                Slog.i(TAG, "BluetoothService");

//新建Bluetoothservice,並把他加入到ServiceManager

                bluetooth = newBluetoothService(context);

               ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE,bluetooth);

//extra1.1在啓動Bluetooth服務後進行一些初始化,呵呵,這裏就對狀態機進行了改變

               bluetooth.initAfterRegistration();

 

//新建了BluetoothA2dpService,並把之加入到了ServiceManager

bluetoothA2dp= new BluetoothA2dpService(context, bluetooth);

               ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,

                                         bluetoothA2dp);

//extra1.2一樣的要在以後作些init的工做

               bluetooth.initAfterA2dpRegistration();

//獲得是否飛行

                int airplaneModeOn =Settings.System.getInt(mContentResolver,

                       Settings.System.AIRPLANE_MODE_ON, 0);

//Bluetooth是否on,如果打開的狀態(沒有飛行),則這裏會調用enable去打開

                int bluetoothOn =Settings.Secure.getInt(mContentResolver,

                   Settings.Secure.BLUETOOTH_ON, 0);

                if (airplaneModeOn == 0&& bluetoothOn != 0) {

                    bluetooth.enable();

                }

            }

 

extra1.1initAfterRegistration分析

 

    public synchronized voidinitAfterRegistration() {

//獲得defaultadapter

        mAdapter =BluetoothAdapter.getDefaultAdapter();

//建立BluetoothAdapterStateMachine,初始化幾個狀態,並設初始狀態位POWEROFF,這裏同時新建了一個EventLoop

        mBluetoothState = newBluetoothAdapterStateMachine(mContext, this, mAdapter);

        mBluetoothState.start();

//根據這個xmlbool變量來決定是否先期TURN_HOT,該變量位於frameworks/base/core/res/res/values/config.xml中,默認爲true

        if (mContext.getResources().getBoolean

           (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {

//extra1.2發送TURN_HOT的狀態變化message

           mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT);

        }

//獲得對應的EventLoop

        mEventLoop =mBluetoothState.getBluetoothEventLoop();

    }

 

extra1.2  TURN_HOT message的處理

 

    /**

     * Bluetooth module's power is off,firmware is not loaded.

     */

    private class PowerOff extends State {

        @Override

        public void enter() {

            if (DBG) log("Enter PowerOff:" + getCurrentMessage().what);

        }

        @Override

        public boolean processMessage(Messagemessage) {

            log("PowerOff process message:" + message.what);

 

            boolean retValue = HANDLED;

            switch(message.what) {

……

               case TURN_HOT:

//extra1.3這裏就是咱們尋找了千年的bt_enable所在的地方。咱們去看看

                    if (prepareBluetooth()) {

//extra1.5轉變狀態到warmup,在prepareBluetooth真正完成後,這個狀態還會發生改變

                        transitionTo(mWarmUp);

                    }

                    break;

……

 

extra1.3prepareBluetooth分析

 

看英文註釋就知道了,不解釋

        /**

         * Turn on Bluetooth Module, Loadfirmware, and do all the preparation

         * needed to get the Bluetooth Moduleready but keep it not discoverable

         * and not connectable.

         * The last step of this method sets upthe local service record DB.

         * There will be a event reporting thestatus of the SDP setup.

         */

        private boolean prepareBluetooth() {

//extra1.4首先仍是調用了enableNative的本地方法,到這裏你會發現終於和2.3類似了(不過請注意調用的時機不一樣了,這個在初始化,而2.3在界面的on/off滑動的時候),它仍是會調用bt_enable,這個就會調用對應的set_bluetooth_power

            if(mBluetoothService.enableNative() != 0) {

                return false;

            }

 

            // try to start event loop, give 2attempts

//嘗試兩次去start event loop

            int retryCount = 2;

            boolean eventLoopStarted = false;

            while ((retryCount-- > 0)&& !eventLoopStarted) {

                mEventLoop.start();

                // it may take a moment for theother thread to do its

                // thing.  Check periodically for a while.

                int pollCount = 5;

                while ((pollCount-- > 0)&& !eventLoopStarted) {

                    if(mEventLoop.isEventLoopRunning()) {

                        eventLoopStarted =true;

                        break;

                    }

                    try {

                        Thread.sleep(100);

                    } catch(InterruptedException e) {

                       log("prepareBluetooth sleep interrupted: " + pollCount);

                        break;

                    }

                }

            }

//出錯處理

            if (!eventLoopStarted) {

               mBluetoothService.disableNative();

                return false;

            }

 

            // get BluetoothService ready

//創建native data以及SDP相關的一些操做,這裏將會產生PropertyChangedUUIDssignal對該信號的處理會對狀態發生改變,詳細分析見extra1.5

            if(!mBluetoothService.prepareBluetooth()) {

                mEventLoop.stop();

               mBluetoothService.disableNative();

                return false;

            }

//設置一個prepare的超時處理,在該時間內沒有收到UUID changedsignal將會進行錯誤處理

           sendMessageDelayed(PREPARE_BLUETOOTH_TIMEOUT,PREPARE_BLUETOOTH_TIMEOUT_TIME);

            return true;

        }

    }

 

extra1.4bt_enable分析

 

intbt_enable() {

    LOGV(__FUNCTION__);

 

    int ret = -1;

    int hci_sock = -1;

    int attempt;

 

//power的設置,on。不解釋,可加入對應板子的gpio口的處理,默認就只用了rfkill的處理

    if (set_bluetooth_power(1) < 0) gotoout;

//開始hciattach服務,這個咱們也作了修改,加入了rtk_h5

    LOGI("Starting hciattachdaemon");

    if (property_set("ctl.start","hciattach") < 0) {

        LOGE("Failed to starthciattach");

        set_bluetooth_power(0);

        goto out;

    }

 

 

    // Try for 10 seconds, this can onlysucceed once hciattach has sent the

    // firmware and then turned on hci devicevia HCIUARTSETPROTO ioctl

    for (attempt = 1000; attempt > 0;  attempt--) {

//建立hci_sock

        hci_sock = create_hci_sock();

        if (hci_sock < 0) goto out;

//調用ioctlHCIDEVUP,來判斷hciattach是否已經ok了。

        ret = ioctl(hci_sock, HCIDEVUP,HCI_DEV_ID);

 

        LOGI("bt_enable: ret: %d, errno:%d", ret, errno);

        if (!ret) {

            break;

        } else if (errno == EALREADY) {

            LOGW("Bluetoothd alreadystarted, unexpectedly!");

            break;

        }

 

        close(hci_sock);

//等待10 ms後再試一次

        usleep(100000);  // 100 ms retry delay

    }

//10s都沒有搞定,須要作個失敗的處理

    if (attempt == 0) {

        LOGE("%s: Timeout waiting for HCIdevice to come up, error- %d, ",

            __FUNCTION__, ret);

        if (property_set("ctl.stop","hciattach") < 0) {

            LOGE("Error stoppinghciattach");

        }

        set_bluetooth_power(0);

        goto out;

    }

//啓動bluetoothd服務

    LOGI("Starting bluetoothddeamon");

    if (property_set("ctl.start","bluetoothd") < 0) {

        LOGE("Failed to startbluetoothd");

        set_bluetooth_power(0);

        goto out;

    }

 

    ret = 0;

 

out:

//關閉hci_sock

    if (hci_sock >= 0) close(hci_sock);

    return ret;

}

 

extra 1.5 PropetyChangedUUIDs的處理

 

event_filter是用來對bluezdbussignal進行監聽的,有signal產生後,會在這裏進行處理。所以,咱們直接到這裏看看該怎麼處理。

 

//Called by dbus during WaitForAndDispatchEventNative()

staticDBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,

                                      void*data) {

    native_data_t *nat;

    JNIEnv *env;

    DBusError err;

    DBusHandlerResult ret;

 

//err的一個初始化

    dbus_error_init(&err);

//獲得參數

    nat = (native_data_t *)data;

    nat->vm->GetEnv((void**)&env,nat->envVer);

    if (dbus_message_get_type(msg) !=DBUS_MESSAGE_TYPE_SIGNAL) {

        LOGV("%s: not interested (not asignal).", __FUNCTION__);

        returnDBUS_HANDLER_RESULT_NOT_YET_HANDLED;

    }

 

    LOGV("%s: Received signal %s:%s from%s", __FUNCTION__,

        dbus_message_get_interface(msg),dbus_message_get_member(msg),

        dbus_message_get_path(msg));

 

    env->PushLocalFrame(EVENT_LOOP_REFS);

……

//PropertyChanged這個signal的處理

    } else if (dbus_message_is_signal(msg,

                                     "org.bluez.Adapter",

                                     "PropertyChanged")) {

//msg解析參數

        jobjectArray str_array =parse_adapter_property_change(env, msg);

        if (str_array != NULL) {

            /* Check if bluetoothd has(re)started, if so update the path. */

            jstring property =(jstring)env->GetObjectArrayElement(str_array, 0);

            const char *c_property =env->GetStringUTFChars(property, NULL);

//檢查Property是否started

            if (!strncmp(c_property,"Powered", strlen("Powered"))) {

//如果powered,則看value是不是true,是ture就獲得對應的path

                jstring value =

                    (jstring)env->GetObjectArrayElement(str_array, 1);

                const char *c_value =env->GetStringUTFChars(value, NULL);

                if (!strncmp(c_value,"true", strlen("true")))

                    nat->adapter =get_adapter_path(nat->conn);

               env->ReleaseStringUTFChars(value, c_value);

            }

           env->ReleaseStringUTFChars(property, c_property);

//extra1.6調用對應的method_onPropertyChanged函數,該method對應的onPropertyChanged函數

            env->CallVoidMethod(nat->me,

                             method_onPropertyChanged,

                              str_array);

        } elseLOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);

        goto success;

……

 

extra1.6真正的處理函數onPropertyChanged分析

 

 /**

     * Called by native code on aPropertyChanged signal from

     * org.bluez.Adapter. This method is alsocalled from

     * {@link BluetoothAdapterStateMachine} toset the "Pairable"

     * property when Bluetooth is enabled.

     *

     * @param propValues a string arraycontaining the key and one or more

     * values.

     */

    /*package*/ void onPropertyChanged(String[]propValues) {

        BluetoothAdapterPropertiesadapterProperties =

               mBluetoothService.getAdapterProperties();

//fill up cache

        if (adapterProperties.isEmpty()) {

            // We have got a property changebefore

            // we filled up our cache.

           adapterProperties.getAllProperties();

        }

        log("Property Changed: " +propValues[0] + " : " + propValues[1]);

        String name = propValues[0];

……

//UUIDs的處理

        } else if(name.equals("Devices") || name.equals("UUIDs")) {

            String value = null;

            int len =Integer.valueOf(propValues[1]);

            if (len > 0) {

                StringBuilder str = newStringBuilder();

                for (int i = 2; i <propValues.length; i++) {

                    str.append(propValues[i]);

                    str.append(",");

                }

                value = str.toString();

            }

//namevalue值加入到propertymap

            adapterProperties.setProperty(name,value);

//extra1.7UUIDschange signal會刷新BluetoothState

            if (name.equals("UUIDs")){

               mBluetoothService.updateBluetoothState(value);

            }

//PairableDiscoverable的處理

       } else if(name.equals("Pairable") || name.equals("Discoverable")) {

            adapterProperties.setProperty(name,propValues[1]);

 

            if(name.equals("Discoverable")) {

   //5.6發送SCAN_MODE_CHANGEDmsg,去改變狀態機      mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SCAN_MODE_CHANGED);

            }

//設置對應的property

            String pairable =name.equals("Pairable") ? propValues[1] :

               adapterProperties.getProperty("Pairable");

            String discoverable =name.equals("Discoverable") ? propValues[1] :

               adapterProperties.getProperty("Discoverable");

 

            // This shouldn't happen, unlessAdapter Properties are null.

            if (pairable == null ||discoverable == null)

                return;

 

            int mode =BluetoothService.bluezStringToScanMode(

                   pairable.equals("true"),

                   discoverable.equals("true"));

            if (mode >= 0) {

//pairablediscoverable均爲true的時候,會發送一個ACTION_SCAN_MODE_CHANGED的廣播消息

                Intent intent = newIntent(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);

            }

        }

 

……

 

extra1.7  UUIDs改變帶來的State的刷新

 

    /**

     * This function is called from BluetoothEvent Loop when onPropertyChanged

     * for adapter comes in with UUID property.

     * @param uuidsThe uuids of adapter asreported by Bluez.

     */

    /*package*/ synchronized voidupdateBluetoothState(String uuids) {

        ParcelUuid[] adapterUuids =convertStringToParcelUuid(uuids);

//爲何必須包含全部已經有的uuid??感受有點反了,再看看

        if (mAdapterUuids != null &&

           BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {

//SERVICE_RECORD_LOADED的信息,此時,處於warm up狀態,看extra1.8分析狀態如何繼續改變          mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);

        }

    }

 

extra1.8 UUIDs對狀態機改變

 

   /**

     * Turning on Bluetooth module's power,loading firmware, starting

     * event loop thread to listen on Bluetoothmodule event changes.

     */

    private class WarmUp extends State {

 

        @Override

        public void enter() {

            if (DBG) log("Enter WarmUp:" + getCurrentMessage().what);

        }

 

        @Override

        public boolean processMessage(Messagemessage) {

            log("WarmUp process message:" + message.what);

 

            boolean retValue = HANDLED;

            switch(message.what) {

                case SERVICE_RECORD_LOADED:

//能夠看到,首先會把當時從poweroff過來的一個超時messageremove了。

                   removeMessages(PREPARE_BLUETOOTH_TIMEOUT);

//轉到hotoff狀態,在hotoff狀態仍會接收到多個SERVICE_RECORD_LOADEDmsg,可是那個狀態下該msg將沒有任何handled,所以會一直處於hotoff狀態

                    transitionTo(mHotOff);

                    break;

……

 

5.2mAdapter.enablemBluetoothState.sendMessage後的狀態機處理

 

extra的分析可知,此時,BluetoothState已經處於HotOff狀態了,因此,從這裏開始處理State的變換。

 

    /**

     * Bluetooth Module has powered, firmwareloaded, event loop started,

     * SDP loaded, but the modules staysnon-discoverable and

     * non-connectable.

     */

    private class HotOff extends State {

        @Override

        public void enter() {

            if (DBG) log("Enter HotOff:" + getCurrentMessage().what);

        }

 

        @Override

        public boolean processMessage(Messagemessage) {

            log("HotOff process message:" + message.what);

 

            boolean retValue = HANDLED;

            switch(message.what) {

                case USER_TURN_ON:

//發出BluetoothAdapter.STATE_TURNING_ON的廣播消息

                   broadcastState(BluetoothAdapter.STATE_TURNING_ON);

                    if ((Boolean) message.obj){

//就是把Settings.Secure.BLUETOOTH_ON設爲1。用於標誌Bluetooth enable

                       persistSwitchSetting(true);

                    }

                    // let it fall toTURN_ON_CONTINUE:

                    //$FALL-THROUGH$

//注意上面沒有break

                case TURN_ON_CONTINUE:

//這裏就是把Bluetooth設爲connectable就是Powered=1,這裏就把prepareBluetooth中設置的不可鏈接從新設置回來了。這個重連會產生一些新的變化它會發送WRITE_SCAN_ENABLEcmd所以在該cmd_complete時會有一些新的處理5.3,它會再次引發狀態機的改變:5.6

                   mBluetoothService.switchConnectable(true);

//進入到Switching狀態

                    transitionTo(mSwitching);

                    break;

……

 

5.3 WRITE_SCAN_ENABLEcmd_complete後的處理

 

bluez中是用cmd_complete函數來監視發出cmd完成後的處理的。該函數具體以下:

 

staticinline void cmd_complete(int index, void *ptr)

{

structdev_info *dev = &devs[index];

evt_cmd_complete*evt = ptr;

uint16_topcode = btohs(evt->opcode);

uint8_tstatus = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE);

 

switch(opcode) {

……

//WRITE_SCAN_ENABLE命令完成的處理函數,會再發一個READ_SCAN_ENABLE的命令

casecmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):

hci_send_cmd(dev->sk,OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,

0,NULL);

break;

//5.4緊接着就是對READ_SCAN_ENABLE命令完成的處理,它是經過read_scan_complete來實現的

casecmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):

ptr+= sizeof(evt_cmd_complete);

read_scan_complete(index,status, ptr);

break;

……

}

 

5.4 read_scan命令完成的處理

 

staticvoid read_scan_complete(int index, uint8_t status, void *ptr)

{

structbtd_adapter *adapter;

read_scan_enable_rp*rp = ptr;

 

DBG("hci%dstatus %u", index, status);

//index獲得對應的adapter

adapter= manager_find_adapter_by_id(index);

if(!adapter) {

error("Unableto find matching adapter");

return;

}

//5.5這裏算是一個通知adaptermode改變了

adapter_mode_changed(adapter,rp->enable);

}

 

5.5通知adaptermode發生了改變

 

voidadapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)

{

constgchar *path = adapter_get_path(adapter);

gbooleandiscoverable, pairable;

 

DBG("old0x%02x new 0x%02x", adapter->scan_mode, scan_mode);

//若相同,則nothing todo

if(adapter->scan_mode == scan_mode){

#ifdefBOARD_HAVE_BLUETOOTH_BCM

    /*we may reset scan_mode already inbtd_adapter_stop(), so comes to here*/

    set_mode_complete(adapter);

#endif

    return;

}

//discoverabletimeout清空

adapter_remove_discov_timeout(adapter);

//這裏開始,是設爲SCAN_PAGE| SCAN_INQUIRY

switch(scan_mode) {

caseSCAN_DISABLED:

adapter->mode= MODE_OFF;

discoverable= FALSE;

pairable= FALSE;

break;

caseSCAN_PAGE:

adapter->mode= MODE_CONNECTABLE;

discoverable= FALSE;

pairable= adapter->pairable;

break;

case(SCAN_PAGE | SCAN_INQUIRY):

//設一下模式,在有reply要求的狀況下,該步驟仍是很重要的

adapter->mode= MODE_DISCOVERABLE;

discoverable= TRUE;

pairable= adapter->pairable;

//還要設一個discoverable的時間

if(adapter->discov_timeout != 0)

adapter_set_discov_timeout(adapter,

adapter->discov_timeout);

break;

caseSCAN_INQUIRY:

/*Address the scenario where a low-level application like

 * hciconfig changed the scan mode */

if(adapter->discov_timeout != 0)

adapter_set_discov_timeout(adapter,

adapter->discov_timeout);

 

/*ignore, this event should not be sent */

default:

/*ignore, reserved */

return;

}

 

/*If page scanning gets toggled emit the Pairable property */

//這裏會發一個property_changedpairablesignal

if((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE))

emit_property_changed(connection,adapter->path,

ADAPTER_INTERFACE,"Pairable",

DBUS_TYPE_BOOLEAN,&pairable);

 

if(!discoverable)

adapter_set_limited_discoverable(adapter,FALSE);

//這裏會發一個property_changeddiscoverablesignal

emit_property_changed(connection,path,

ADAPTER_INTERFACE,"Discoverable",

DBUS_TYPE_BOOLEAN,&discoverable);

adapter->scan_mode= scan_mode;

 

set_mode_complete(adapter);

}

 

5.6 WRTIE_SCAN_ENABLE最終引發的狀態機的變化

 

在此以前,狀態機處於switching的狀態,收到了SCAN_MODE_CHANGEDmsg

 

    private class Switching extends State {

 

        @Override

        public void enter() {

            if (DBG) log("Enter Switching:" + getCurrentMessage().what);

        }

        @Override

        public boolean processMessage(Messagemessage) {

            log("Switching processmessage: " + message.what);

 

            boolean retValue = HANDLED;

            switch(message.what) {

                case SCAN_MODE_CHANGED:

                    // This event matchesmBluetoothService.switchConnectable action

//mPublicStatehotoffswtiching狀態變化時已經被設爲STATE_TURNING_ON了,因此這裏if沒有問題

                    if (mPublicState ==BluetoothAdapter.STATE_TURNING_ON) {

                        // set pairable if it'snot

//設置爲pairable假如尚未設置的話,這個會先在bluez中檢查一下當前是否pairable,咱們在前面已經設置好了,因此,這裏只是一個檢查而已,沒有什麼實際性的工做

                       mBluetoothService.setPairable();

//初始化bond stateprofile state,這個會在adapter pairable以後,bluetooth turn on以前發生

                       mBluetoothService.initBluetoothAfterTurningOn();

//這邊正式進入到bluetoothon的狀態,終於進了這裏,哎。。。

                       transitionTo(mBluetoothOn);

//發送STATE_ONbroadcast

                       broadcastState(BluetoothAdapter.STATE_ON);

                        // run bluetooth nowthat it's turned on

                        // Note runBluetoothshould be called only in adapter STATE_ON

//鏈接那些能夠自動鏈接的設備,通知battery,藍牙打開了

                       mBluetoothService.runBluetooth();

                    }

                    break;

……

 

至此,藍牙的使能主要過程已經所有搞定。

相關文章
相關標籤/搜索