此博客是轉載過來的哦。。。 java
給本身博客定幾個部分: android
(1)寫在前面的話:一些寫博客時的廢話。 app
(2)內容簡介:把文章的主要內容或者核心部分做一個框架性的歸納,以方便你們閱讀。 框架
(3)正文:這個不須要解釋了。 less
寫在前面的話:這是csdn上的第一篇博客,但願本身可以堅持寫下去,也但願可以獲得你們的支持。本文可能會涉及大量的源碼註釋,在文字方面可能不夠盡如人意,但願真正想理解該過程的同窗們可以耐心看下去。 ide
內容簡介:本文詳細分析了android4.0中藍牙使能的過程,相比較android2.3,4.0中的藍牙最大的差異在於UI上on/off的僞開關。在android4.0中加入了adapter的狀態機。所謂的狀態機就相似於狀態轉換圖,在一個狀態收到某個特定的命令會變成另一個狀態,不一樣的命令能夠跳轉到不一樣的狀態(固然也有可能到同一狀態)。adapter的初始狀態爲poweroff,在android系統啓動的時候會進入warmup狀態,同時會進行UUID的add,該操做會引發propertychanged的UUID signal,該signal會使得狀態從warmup變換到hotoff狀態。所以在UI端off時其實adapter已經處於hotoff狀態而不是poweroff狀態。這一點是很關鍵的。在正文中,我會從假如我不知道這些開始來描繪整個使能的過程。 函數
正文: oop
毫無疑問,bluetooth的打開是在Settings中進行的操做。所以,冤有頭,債有主,咱們來到了Settings.java中,果真發現了相關的代碼以下: 測試
mBluetoothEnabler =new BluetoothEnabler(context, new Switch(context));ui
因而,咱們得以進入真正的藍牙操做的殿堂,好好進去看看吧。
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;
……
至此,藍牙的使能主要過程已經所有搞定。此博客是轉載過來的哦。。。
給本身博客定幾個部分:
(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.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;
……
至此,藍牙的使能主要過程已經所有搞定。此博客是轉載過來的哦。。。
給本身博客定幾個部分:
(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.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;
……
至此,藍牙的使能主要過程已經所有搞定。