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;

……

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

时间: 2024-08-23 19:29:28

android4.0蓝牙使能的详细解析的相关文章

android4.0蓝牙使能的详细解析 (转载)

此博客是转载过来的哦... 给自己博客定几个部分: (1)写在前面的话:一些写博客时的废话. (2)内容简介:把文章的主要内容或者核心部分作一个框架性的概括,以方便大家阅读. (3)正文:这个不需要解释了.   写在前面的话:这是csdn上的第一篇博客,希望自己能够坚持写下去,也希望能够得到大家的支持.本文可能会涉及大量的源码注释,在文字方面可能不够尽如人意,希望真正想理解该过程的同学们能够耐心看下去. 内容简介:本文详细分析了android4.0中蓝牙使能的过程,相比较android2.3,4

android4.0蓝牙使能的详细解析(转)

源:http://www.cnblogs.com/xiaochao1234/p/3818193.html 本文详细分析了android4.0 中蓝牙使能的过程,相比较android2.3,4.0中的蓝牙最大的差别在于UI上on/off的伪开关.在android4.0中加入了 adapter的状态机.所谓的状态机就类似于状态转换图,在一个状态收到某个特定的命令会变成另外一个状态,不同的命令可以跳转到不同的状态(当然也有 可能到同一状态).adapter的初始状态为poweroff,在android

在Linux7.0下创建论坛详细步骤解析

   在Linux7.0下创建论坛详细步骤解析具体内容查看附件. 如有错误,希望可以反馈回来,谢谢!          

详细解析BluetoothAdapter的详细api

(1)开关状态值 (2)扫描状态值 (3)蓝牙操作接收的广播 (4)蓝牙操作请求的广播 (5)附加域 (6)错误码 (1)获取蓝牙适配器 (2)获取state状态方法 (3)蓝牙是否可用 (4)打开蓝牙 (5)关闭蓝牙 (1)开始扫描 (2)是否在扫描中 (3)取消查找 (4)获取扫描模式 (1)检查蓝牙地址 (2)获取本地蓝牙地址 (3)获取本地蓝牙名称 (4)获取绑定的蓝牙集合 (5)获取远程蓝牙设备 (6)创建监听 这篇文章将会详细解析BluetoothAdapter的详细api, 包括隐

【转】UML中的几种关系详细解析

UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现 类与类图 1) 类(Class)封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性.操作.关系的对象集合的总称. 2) 在系统中,每个类具有一定的职责,职责指的是类所担任的任务,即类要完成什么样的功能,要承担什么样的义务.一个类可以有多种职责,设计得好的类一般只有一种职责,在定义类的时候,将类的职责分解成为类的属性和操作(即方法). 3) 类的属性即类的数据职责,类的操作即类的行为职责 一.依赖关系(Dependence) 依

字符数组的定义与使用详细解析

1. 字符数组的定义: 用来存放字符量的数组称为字符数组. 形式数值数组相同.例如: char c[10]; 由于字符型和整型通用,也可以定义为int c[10],但这时每个数组元素占2个字节的内存单元. 字符数组也可以是二维或多维数组.例如: char c[5][10]; 即为二维字符数组. 2. 字符数组的初始化 第一种方法是分别对每一个元素进行赋值操作: 字符数组也允许在定义时作初始化赋值.例如: char c[10]={'c', '  ', 'p', 'r','o', 'g', 'r',

Android4.0 input事件输入流程详解(中间层到应用层)

在Android系统中,类似于键盘按键.触摸屏等事件是由WindowManagerService服务来管理的,然后再以消息的形式来分发给应用程序进行处理.系统启动时,窗口管理服务也会启动,该服务启动过程中,会通过系统输入管理器InputManager来负责监控键盘消息.当某一个Activity激活时,会在该Service下注册一个接收消息的通道,表明可以处理具体的消息,然后当有消息时,InputManager就会分发给当前处于激活状态下的Activity进行处理. InputManager的启动

Android4.0设置界面修改总结(四)

之前有跟大家分享设置Tab风格和Item圆角的实现,希望能给有需要的朋友一点点帮助,今天再和大家分享一下用ViewPager实现设置分页,小米和OPPO就是这样的设置,先来看看效果图:   为了帮助大家更清晰的理解,我单独拿出一个小例子,有需要的朋友可以下载下来看看: http://git.oschina.net/way/SettingTab/tree/master 其实要实现这样的风格并不难,只要能比较深入的理解PreferenceActivity.java就可以了.我们都知道Settings

java类生命周期详细解析

(一)详解java类的生命周期 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你“怎样做”,但至于“为什么这样做”却不多说,所以造成大家在基础和原理方面的知识比较匮乏,所以笔者今天就斗胆来讲一下这个问题,权当抛砖引玉,希望对在这个问题上有疑惑的朋友有所帮助,文中有说的不对的地方,也希望各路高手前来指正. 首先来了解一下jvm(java虚拟机)