zoukankan      html  css  js  c++  java
  • android4.0蓝牙使能的详细解析 (转载)

    此博客是转载过来的哦。。。

    给自己博客定几个部分:

    (1)写在前面的话:一些写博客时的废话。

    (2)内容简介:把文章的主要内容或者核心部分作一个框架性的概括,以方便大家阅读。

    (3)正文:这个不需要解释了。

     

    写在前面的话:这是csdn上的第一篇博客,希望自己能够坚持写下去,也希望能够得到大家的支持。本文可能会涉及大量的源码注释,在文字方面可能不够尽如人意,希望真正想理解该过程的同学们能够耐心看下去。

    内容简介:本文详细分析了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状态。这一点是很关键的。在正文中,我会从假如我不知道这些开始来描绘整个使能的过程。

    正文:

    毫无疑问,bluetooth的打开是在Settings中进行的操作。因此,冤有头,债有主,我们来到了Settings.java中,果然发现了相关的代码如下:

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

    于是,我们得以进入真正的蓝牙操作的殿堂,好好进去看看吧。

     

    1、BluetoothEnabler的构造函数

     

        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得到bluetooth的adapter

                mLocalAdapter =manager.getBluetoothAdapter();

            }

    //同时新建一个intent,用于接收ACTION_STATE_CHANGED

            mIntentFilter = newIntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

        }

     

    2、LocalBluetoothManager类的getInstance

     

        public static synchronizedLocalBluetoothManager getInstance(Context context) {

            if (sInstance == null) {

    //2.1同样的,这个会去调用LocalBluetoothAdapter的getInstance,也会构造该类

                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.1LocalBluetoothAdapter的getInstance

     

        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进行初始化,这个在LocalBluetoothProfileManager的addProfile中实现

            mProfileIntentFilter = newIntentFilter();

    //创建一个Handler的Hash表

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

            mContext = context;

     

    //注册对adapter和Device的几个广播消息的处理回调函数

    //add action到mAdapterIntentFilter

            // 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,根据uuid来add并new对应的profile,只针对A2DP,HFP,HSP,OPP四个profile,HID和PAN在下面,每次都add

                updateLocalProfiles(uuids);

            }

     

            // Always add HID and PAN profiles

    //加入HID和PAN两个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_);

                        }

     

    3、mBluetoothEnabler.setSwitch分析

     

        public void setSwitch(Switch switch_) {

    //若是和上次相同,则不做任何事情,可以理解,代码也懒嘛

            if (mSwitch == switch_) return;

    //把上次的switch的changelistener清空

           mSwitch.setOnCheckedChangeListener(null);

            mSwitch = switch_;

    //重设这次的switch的changelistener

           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);

            }

        }

     

    4、onCheckedChanged

    在switch状态发生改变后,会调用这个地方的回调函数进行处理。

     

        public void onCheckedChanged(CompoundButtonbuttonView, boolean isChecked) {

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

    //若是打开的话,就需要检查一下是否allow Bluetooth(radio,airplane的check)

            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

    //若是不对的话,reset为off

                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();

            }

        }

    }

     

    5、mAdapter.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去调用native的bt_enable,而4.0没有这么做。没事,我们来分析4.0怎么做的。

           mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON,saveSetting);

            return true;

        }

     

    5.1mBluetoothState.sendMessage

     

    简单理解一下,mBluetoothState是BluetoothAdapterStateMachine类。因此,在分析的之前,简单说一下,它其实就是类似一个状态转换图,根据你所处于的状态,然后再判断收到的操作,进行不同的处理。根据构造函数中的setInitialState(mPowerOff);可以知道初始状态是PowerOff。但是从它给出的状态机可以看出,在PowerOff的状态时,它是通过TURN_HOT/TURN_ON来改变到HotOff状态的,然后才会收到USER_TURN_ON,去该变到BluetootOn的状态。因此,可以肯定的是我们这里的USER_TURN_ON不是它收到的第一个message,因此我们去纠结一下它是从哪里开始改变PowerOff的状态:extra1,然后再来看这里的处理吧:5.2。

     

    extra1、mAdapter.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() {

    //得到default的adapter

            mAdapter =BluetoothAdapter.getDefaultAdapter();

    //创建BluetoothAdapterStateMachine,初始化几个状态,并设初始状态位POWEROFF,这里同时新建了一个EventLoop

            mBluetoothState = newBluetoothAdapterStateMachine(mContext, this, mAdapter);

            mBluetoothState.start();

    //根据这个xml的bool变量来决定是否先期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相关的一些操作,这里将会产生PropertyChanged的UUIDs的signal,对该信号的处理会对状态发生改变,详细分析见extra1.5

                if(!mBluetoothService.prepareBluetooth()) {

                    mEventLoop.stop();

                   mBluetoothService.disableNative();

                    return false;

                }

    //设置一个prepare的超时处理,在该时间内没有收到UUID changed的signal将会进行错误处理

               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;

    //调用ioctl的HCIDEVUP,来判断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 PropetyChanged的UUIDs的处理

     

    event_filter是用来对bluez的dbus的signal进行监听的,有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();

                }

    //把name和value值加入到property的map中

                adapterProperties.setProperty(name,value);

    //extra1.7有UUIDs的change signal会刷新Bluetooth的State

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

                   mBluetoothService.updateBluetoothState(value);

                }

    //对Pairable和Discoverable的处理

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

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

     

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

       //5.6发送SCAN_MODE_CHANGED的msg,去改变状态机      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) {

    //当pairable和discoverable均为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过来的一个超时message拿remove了。

                       removeMessages(PREPARE_BLUETOOTH_TIMEOUT);

    //转到hotoff状态,在hotoff状态仍会接收到多个SERVICE_RECORD_LOADED的msg,但是那个状态下该msg将没有任何handled,因此会一直处于hotoff状态

                        transitionTo(mHotOff);

                        break;

    ……

     

    5.2mAdapter.enablemBluetoothState.sendMessage后的状态机处理

     

    由extra的分析可知,此时,Bluetooth的State已经处于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_ENABLE的cmd,因此在该cmd_complete时会有一些新的处理:5.3,它会再次引起状态机的改变:5.6

                       mBluetoothService.switchConnectable(true);

    //进入到Switching状态

                        transitionTo(mSwitching);

                        break;

    ……

     

    5.3 WRITE_SCAN_ENABLE在cmd_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这里算是一个通知adapter,mode改变了。

    adapter_mode_changed(adapter,rp->enable);

    }

     

    5.5通知adapter,mode发生了改变

     

    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;

    }

    //把discoverable的timeout清空

    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_changed的pairable的signal

    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_changed的discoverable的signal

    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_CHANGED的msg。

     

        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

    //mPublicState在hotoff到swtiching状态变化时已经被设为STATE_TURNING_ON了,所以这里if没有问题

                        if (mPublicState ==BluetoothAdapter.STATE_TURNING_ON) {

                            // set pairable if it'snot

    //设置为pairable假如还没有设置的话,这个会先在bluez中检查一下当前是否pairable,我们在前面已经设置好了,所以,这里只是一个检查而已,没有什么实际性的工作

                           mBluetoothService.setPairable();

    //初始化bond state和profile state,这个会在adapter pairable之后,bluetooth turn on之前发生

                           mBluetoothService.initBluetoothAfterTurningOn();

    //这边正式进入到bluetoothon的状态,终于进了这里,哎。。。

                           transitionTo(mBluetoothOn);

    //发送STATE_ON的broadcast

                           broadcastState(BluetoothAdapter.STATE_ON);

                            // run bluetooth nowthat it's turned on

                            // Note runBluetoothshould be called only in adapter STATE_ON

    //连接那些可以自动连接的设备,通知battery,蓝牙打开了

                           mBluetoothService.runBluetooth();

                        }

                        break;

    ……

     

    至此,蓝牙的使能主要过程已经全部搞定。此博客是转载过来的哦。。。

    给自己博客定几个部分:

    (1)写在前面的话:一些写博客时的废话。

    (2)内容简介:把文章的主要内容或者核心部分作一个框架性的概括,以方便大家阅读。

    (3)正文:这个不需要解释了。

     

    写在前面的话:这是csdn上的第一篇博客,希望自己能够坚持写下去,也希望能够得到大家的支持。本文可能会涉及大量的源码注释,在文字方面可能不够尽如人意,希望真正想理解该过程的同学们能够耐心看下去。

    内容简介:本文详细分析了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状态。这一点是很关键的。在正文中,我会从假如我不知道这些开始来描绘整个使能的过程。

    正文:

    毫无疑问,bluetooth的打开是在Settings中进行的操作。因此,冤有头,债有主,我们来到了Settings.java中,果然发现了相关的代码如下:

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

    于是,我们得以进入真正的蓝牙操作的殿堂,好好进去看看吧。

     

    1、BluetoothEnabler的构造函数

     

        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得到bluetooth的adapter

                mLocalAdapter =manager.getBluetoothAdapter();

            }

    //同时新建一个intent,用于接收ACTION_STATE_CHANGED

            mIntentFilter = newIntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

        }

     

    2、LocalBluetoothManager类的getInstance

     

        public static synchronizedLocalBluetoothManager getInstance(Context context) {

            if (sInstance == null) {

    //2.1同样的,这个会去调用LocalBluetoothAdapter的getInstance,也会构造该类

                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.1LocalBluetoothAdapter的getInstance

     

        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进行初始化,这个在LocalBluetoothProfileManager的addProfile中实现

            mProfileIntentFilter = newIntentFilter();

    //创建一个Handler的Hash表

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

            mContext = context;

     

    //注册对adapter和Device的几个广播消息的处理回调函数

    //add action到mAdapterIntentFilter

            // 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,根据uuid来add并new对应的profile,只针对A2DP,HFP,HSP,OPP四个profile,HID和PAN在下面,每次都add

                updateLocalProfiles(uuids);

            }

     

            // Always add HID and PAN profiles

    //加入HID和PAN两个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_);

                        }

     

    3、mBluetoothEnabler.setSwitch分析

     

        public void setSwitch(Switch switch_) {

    //若是和上次相同,则不做任何事情,可以理解,代码也懒嘛

            if (mSwitch == switch_) return;

    //把上次的switch的changelistener清空

           mSwitch.setOnCheckedChangeListener(null);

            mSwitch = switch_;

    //重设这次的switch的changelistener

           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);

            }

        }

     

    4、onCheckedChanged

    在switch状态发生改变后,会调用这个地方的回调函数进行处理。

     

        public void onCheckedChanged(CompoundButtonbuttonView, boolean isChecked) {

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

    //若是打开的话,就需要检查一下是否allow Bluetooth(radio,airplane的check)

            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

    //若是不对的话,reset为off

                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();

            }

        }

    }

     

    5、mAdapter.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去调用native的bt_enable,而4.0没有这么做。没事,我们来分析4.0怎么做的。

           mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON,saveSetting);

            return true;

        }

     

    5.1mBluetoothState.sendMessage

     

    简单理解一下,mBluetoothState是BluetoothAdapterStateMachine类。因此,在分析的之前,简单说一下,它其实就是类似一个状态转换图,根据你所处于的状态,然后再判断收到的操作,进行不同的处理。根据构造函数中的setInitialState(mPowerOff);可以知道初始状态是PowerOff。但是从它给出的状态机可以看出,在PowerOff的状态时,它是通过TURN_HOT/TURN_ON来改变到HotOff状态的,然后才会收到USER_TURN_ON,去该变到BluetootOn的状态。因此,可以肯定的是我们这里的USER_TURN_ON不是它收到的第一个message,因此我们去纠结一下它是从哪里开始改变PowerOff的状态:extra1,然后再来看这里的处理吧:5.2。

     

    extra1、mAdapter.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() {

    //得到default的adapter

            mAdapter =BluetoothAdapter.getDefaultAdapter();

    //创建BluetoothAdapterStateMachine,初始化几个状态,并设初始状态位POWEROFF,这里同时新建了一个EventLoop

            mBluetoothState = newBluetoothAdapterStateMachine(mContext, this, mAdapter);

            mBluetoothState.start();

    //根据这个xml的bool变量来决定是否先期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相关的一些操作,这里将会产生PropertyChanged的UUIDs的signal,对该信号的处理会对状态发生改变,详细分析见extra1.5

                if(!mBluetoothService.prepareBluetooth()) {

                    mEventLoop.stop();

                   mBluetoothService.disableNative();

                    return false;

                }

    //设置一个prepare的超时处理,在该时间内没有收到UUID changed的signal将会进行错误处理

               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;

    //调用ioctl的HCIDEVUP,来判断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 PropetyChanged的UUIDs的处理

     

    event_filter是用来对bluez的dbus的signal进行监听的,有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();

                }

    //把name和value值加入到property的map中

                adapterProperties.setProperty(name,value);

    //extra1.7有UUIDs的change signal会刷新Bluetooth的State

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

                   mBluetoothService.updateBluetoothState(value);

                }

    //对Pairable和Discoverable的处理

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

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

     

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

       //5.6发送SCAN_MODE_CHANGED的msg,去改变状态机      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) {

    //当pairable和discoverable均为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过来的一个超时message拿remove了。

                       removeMessages(PREPARE_BLUETOOTH_TIMEOUT);

    //转到hotoff状态,在hotoff状态仍会接收到多个SERVICE_RECORD_LOADED的msg,但是那个状态下该msg将没有任何handled,因此会一直处于hotoff状态

                        transitionTo(mHotOff);

                        break;

    ……

     

    5.2mAdapter.enablemBluetoothState.sendMessage后的状态机处理

     

    由extra的分析可知,此时,Bluetooth的State已经处于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_ENABLE的cmd,因此在该cmd_complete时会有一些新的处理:5.3,它会再次引起状态机的改变:5.6

                       mBluetoothService.switchConnectable(true);

    //进入到Switching状态

                        transitionTo(mSwitching);

                        break;

    ……

     

    5.3 WRITE_SCAN_ENABLE在cmd_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这里算是一个通知adapter,mode改变了。

    adapter_mode_changed(adapter,rp->enable);

    }

     

    5.5通知adapter,mode发生了改变

     

    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;

    }

    //把discoverable的timeout清空

    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_changed的pairable的signal

    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_changed的discoverable的signal

    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_CHANGED的msg。

     

        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

    //mPublicState在hotoff到swtiching状态变化时已经被设为STATE_TURNING_ON了,所以这里if没有问题

                        if (mPublicState ==BluetoothAdapter.STATE_TURNING_ON) {

                            // set pairable if it'snot

    //设置为pairable假如还没有设置的话,这个会先在bluez中检查一下当前是否pairable,我们在前面已经设置好了,所以,这里只是一个检查而已,没有什么实际性的工作

                           mBluetoothService.setPairable();

    //初始化bond state和profile state,这个会在adapter pairable之后,bluetooth turn on之前发生

                           mBluetoothService.initBluetoothAfterTurningOn();

    //这边正式进入到bluetoothon的状态,终于进了这里,哎。。。

                           transitionTo(mBluetoothOn);

    //发送STATE_ON的broadcast

                           broadcastState(BluetoothAdapter.STATE_ON);

                            // run bluetooth nowthat it's turned on

                            // Note runBluetoothshould be called only in adapter STATE_ON

    //连接那些可以自动连接的设备,通知battery,蓝牙打开了

                           mBluetoothService.runBluetooth();

                        }

                        break;

    ……

     

    至此,蓝牙的使能主要过程已经全部搞定。此博客是转载过来的哦。。。

    给自己博客定几个部分:

    (1)写在前面的话:一些写博客时的废话。

    (2)内容简介:把文章的主要内容或者核心部分作一个框架性的概括,以方便大家阅读。

    (3)正文:这个不需要解释了。

     

    写在前面的话:这是csdn上的第一篇博客,希望自己能够坚持写下去,也希望能够得到大家的支持。本文可能会涉及大量的源码注释,在文字方面可能不够尽如人意,希望真正想理解该过程的同学们能够耐心看下去。

    内容简介:本文详细分析了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状态。这一点是很关键的。在正文中,我会从假如我不知道这些开始来描绘整个使能的过程。

    正文:

    毫无疑问,bluetooth的打开是在Settings中进行的操作。因此,冤有头,债有主,我们来到了Settings.java中,果然发现了相关的代码如下:

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

    于是,我们得以进入真正的蓝牙操作的殿堂,好好进去看看吧。

     

    1、BluetoothEnabler的构造函数

     

        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得到bluetooth的adapter

                mLocalAdapter =manager.getBluetoothAdapter();

            }

    //同时新建一个intent,用于接收ACTION_STATE_CHANGED

            mIntentFilter = newIntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

        }

     

    2、LocalBluetoothManager类的getInstance

     

        public static synchronizedLocalBluetoothManager getInstance(Context context) {

            if (sInstance == null) {

    //2.1同样的,这个会去调用LocalBluetoothAdapter的getInstance,也会构造该类

                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.1LocalBluetoothAdapter的getInstance

     

        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进行初始化,这个在LocalBluetoothProfileManager的addProfile中实现

            mProfileIntentFilter = newIntentFilter();

    //创建一个Handler的Hash表

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

            mContext = context;

     

    //注册对adapter和Device的几个广播消息的处理回调函数

    //add action到mAdapterIntentFilter

            // 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,根据uuid来add并new对应的profile,只针对A2DP,HFP,HSP,OPP四个profile,HID和PAN在下面,每次都add

                updateLocalProfiles(uuids);

            }

     

            // Always add HID and PAN profiles

    //加入HID和PAN两个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_);

                        }

     

    3、mBluetoothEnabler.setSwitch分析

     

        public void setSwitch(Switch switch_) {

    //若是和上次相同,则不做任何事情,可以理解,代码也懒嘛

            if (mSwitch == switch_) return;

    //把上次的switch的changelistener清空

           mSwitch.setOnCheckedChangeListener(null);

            mSwitch = switch_;

    //重设这次的switch的changelistener

           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);

            }

        }

     

    4、onCheckedChanged

    在switch状态发生改变后,会调用这个地方的回调函数进行处理。

     

        public void onCheckedChanged(CompoundButtonbuttonView, boolean isChecked) {

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

    //若是打开的话,就需要检查一下是否allow Bluetooth(radio,airplane的check)

            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

    //若是不对的话,reset为off

                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();

            }

        }

    }

     

    5、mAdapter.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去调用native的bt_enable,而4.0没有这么做。没事,我们来分析4.0怎么做的。

           mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON,saveSetting);

            return true;

        }

     

    5.1mBluetoothState.sendMessage

     

    简单理解一下,mBluetoothState是BluetoothAdapterStateMachine类。因此,在分析的之前,简单说一下,它其实就是类似一个状态转换图,根据你所处于的状态,然后再判断收到的操作,进行不同的处理。根据构造函数中的setInitialState(mPowerOff);可以知道初始状态是PowerOff。但是从它给出的状态机可以看出,在PowerOff的状态时,它是通过TURN_HOT/TURN_ON来改变到HotOff状态的,然后才会收到USER_TURN_ON,去该变到BluetootOn的状态。因此,可以肯定的是我们这里的USER_TURN_ON不是它收到的第一个message,因此我们去纠结一下它是从哪里开始改变PowerOff的状态:extra1,然后再来看这里的处理吧:5.2。

     

    extra1、mAdapter.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() {

    //得到default的adapter

            mAdapter =BluetoothAdapter.getDefaultAdapter();

    //创建BluetoothAdapterStateMachine,初始化几个状态,并设初始状态位POWEROFF,这里同时新建了一个EventLoop

            mBluetoothState = newBluetoothAdapterStateMachine(mContext, this, mAdapter);

            mBluetoothState.start();

    //根据这个xml的bool变量来决定是否先期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相关的一些操作,这里将会产生PropertyChanged的UUIDs的signal,对该信号的处理会对状态发生改变,详细分析见extra1.5

                if(!mBluetoothService.prepareBluetooth()) {

                    mEventLoop.stop();

                   mBluetoothService.disableNative();

                    return false;

                }

    //设置一个prepare的超时处理,在该时间内没有收到UUID changed的signal将会进行错误处理

               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;

    //调用ioctl的HCIDEVUP,来判断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 PropetyChanged的UUIDs的处理

     

    event_filter是用来对bluez的dbus的signal进行监听的,有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();

                }

    //把name和value值加入到property的map中

                adapterProperties.setProperty(name,value);

    //extra1.7有UUIDs的change signal会刷新Bluetooth的State

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

                   mBluetoothService.updateBluetoothState(value);

                }

    //对Pairable和Discoverable的处理

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

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

     

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

       //5.6发送SCAN_MODE_CHANGED的msg,去改变状态机      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) {

    //当pairable和discoverable均为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过来的一个超时message拿remove了。

                       removeMessages(PREPARE_BLUETOOTH_TIMEOUT);

    //转到hotoff状态,在hotoff状态仍会接收到多个SERVICE_RECORD_LOADED的msg,但是那个状态下该msg将没有任何handled,因此会一直处于hotoff状态

                        transitionTo(mHotOff);

                        break;

    ……

     

    5.2mAdapter.enablemBluetoothState.sendMessage后的状态机处理

     

    由extra的分析可知,此时,Bluetooth的State已经处于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_ENABLE的cmd,因此在该cmd_complete时会有一些新的处理:5.3,它会再次引起状态机的改变:5.6

                       mBluetoothService.switchConnectable(true);

    //进入到Switching状态

                        transitionTo(mSwitching);

                        break;

    ……

     

    5.3 WRITE_SCAN_ENABLE在cmd_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这里算是一个通知adapter,mode改变了。

    adapter_mode_changed(adapter,rp->enable);

    }

     

    5.5通知adapter,mode发生了改变

     

    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;

    }

    //把discoverable的timeout清空

    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_changed的pairable的signal

    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_changed的discoverable的signal

    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_CHANGED的msg。

     

        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

    //mPublicState在hotoff到swtiching状态变化时已经被设为STATE_TURNING_ON了,所以这里if没有问题

                        if (mPublicState ==BluetoothAdapter.STATE_TURNING_ON) {

                            // set pairable if it'snot

    //设置为pairable假如还没有设置的话,这个会先在bluez中检查一下当前是否pairable,我们在前面已经设置好了,所以,这里只是一个检查而已,没有什么实际性的工作

                           mBluetoothService.setPairable();

    //初始化bond state和profile state,这个会在adapter pairable之后,bluetooth turn on之前发生

                           mBluetoothService.initBluetoothAfterTurningOn();

    //这边正式进入到bluetoothon的状态,终于进了这里,哎。。。

                           transitionTo(mBluetoothOn);

    //发送STATE_ON的broadcast

                           broadcastState(BluetoothAdapter.STATE_ON);

                            // run bluetooth nowthat it's turned on

                            // Note runBluetoothshould be called only in adapter STATE_ON

    //连接那些可以自动连接的设备,通知battery,蓝牙打开了

                           mBluetoothService.runBluetooth();

                        }

                        break;

    ……

     

    至此,蓝牙的使能主要过程已经全部搞定。

  • 相关阅读:
    听较强节奏的歌曲,能让你更长时间投入到学习中
    小康网站维护笔记
    apache基础
    python安装多版本
    apache负载调优
    docker 进阶
    openstack 网络更改版
    linux 搭建testlink的问题总结
    26. Remove Duplicates from Sorted Array(LeetCode)
    Add to List 172. Factorial Trailing Zeroes(LeetCode)
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4602959.html
Copyright © 2011-2022 走看看