Android4.0蓝牙使能的详细解析

毫无疑问,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.enable中mBluetoothState.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;
 
……
复制代码

 


本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/4980587.html,如需转载请自行联系原作者


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值