第三章,苦盡甘來之再次回到jni之上
經過了上面兩章的分析,我們基本已經對一次的“下鄉活動”了解清楚了,下面我們就要詳細分析再次回到jni之上的一些操作了。再這之前,我們先來看看這次下鄉活動從鄉下都帶來了什麼?
其實很少蠻清晰的,就是帶回來了幾個property change的event,他們分別是UUIDs,pairable=false,powered=false,class, discoverable=false。我們來看一下,他們對上層都有哪些影響。
eventloop中對property change的處理函數是:
/*package*/ void onPropertyChanged(String[] propValues) {
所以,我們要分析各個propertychange的影響分析這個函數就可以了。下面,我們來具體分析這些property change的影響:
1、UUIDs的處理
[cpp]
} else if (name.equals("Devices") || name.equals("UUIDs")) {
String value = null;
int len = Integer.valueOf(propValues[1]);
if (len > 0) {
StringBuilder str = new StringBuilder();
for (int i = 2; i < propValues.length; i++) {
str.append(propValues[i]);
str.append(",");
}
value = str.toString();
}
//加入到property中,把UUIDs和對應的value保存
adapterProperties.setProperty(name, value);
if (name.equals("UUIDs")) {
//若是uuid,這個函數是很重要的
mBluetoothService.updateBluetoothState(value);
}
1.2 mBluetoothService.updateBluetoothState(value)函數分析
[cpp]
/*package*/ synchronized void updateBluetoothState(String uuids) {
ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
//當uuid都被注冊成功之後,就可以發送SERVICE_RECORD_LOADED的msg了
if (mAdapterUuids != null &&
BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);
}
}
所以,UUIDs的property change的最終目的就是發送SERVICE_RECORD_LOADED的msg,這個msg是從warmup到hotoff的關鍵條件,這個我們在藍牙的狀態機裡面有詳細分析,不過,我們不妨在這裡也再次分析一下:
[cpp]
switch(message.what) {
case SERVICE_RECORD_LOADED:
removeMessages(PREPARE_BLUETOOTH_TIMEOUT);
//轉換到hotoff的狀態
transitionTo(mHotOff);
break;
到了hotoff狀態之後,我們需要繼續處理在poweroff狀態中傳入的turnon continue的msg:
case TURN_ON_CONTINUE:
//這個就是設置powered為true
mBluetoothService.switchConnectable(true);
transitionTo(mSwitching);
break;
//從注釋來看,這裡是用來設置connectable和pairable的,又要到jni層之下,不過我們直接去看吧,就沒有必要再分開分析了。
/*package*/ synchronized void switchConnectable(boolean on) {
setAdapterPropertyBooleanNative("Powered", on ? 1 : 0);
1.3 bluez中set property的powered的處理
這個函數是處理很多property的不同的,所以,這裡我們直接分析powered的處理。
[cpp]
} else if (g_str_equal("Powered", property)) {
gboolean powered;
//得到參數,這裡就是1了
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
return btd_error_invalid_args(msg);
dbus_message_iter_get_basic(&sub, &powered);
//調用這個函數
return set_powered(conn, msg, powered, data);
}
下面就來看一下set_powered都做了些什麼:
static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
gboolean powered, void *data)
{
struct btd_adapter *adapter = data;
uint8_t mode;
int err;
//就是先這個了
if (powered) {
//mode是off
mode = get_mode(&adapter->bdaddr, "on");
//所以,這個地方是傳入的false
return set_discoverable(conn, msg, mode == MODE_DISCOVERABLE,
data);
}
……
return NULL;
}
static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg,
gboolean discoverable, void *data)
{
struct btd_adapter *adapter = data;
uint8_t mode;
int err;
//這裡discoverable是0,所以mode connectable
mode = discoverable ? MODE_DISCOVERABLE : MODE_CONNECTABLE;
//adapter的mode是off
if (mode == adapter->mode) {
adapter->global_mode = mode;
return dbus_message_new_method_return(msg);
}
//這裡adapter的mode是off,mode是iteconnectable
err = set_mode(adapter, mode, msg);
/* when called by discov_timeout_handler(), msg may be NULL, and cause dbus error */
if (err < 0 && msg != NULL)
return btd_error_failed(msg, strerror(-err));
return NULL;
}
繼續看
static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
DBusMessage *msg)
{
int err;
const char *modestr;
if (adapter->pending_mode != NULL)
return -EALREADY;
//我們是肯定up了,new mode為connectable
if (!adapter->up && new_mode != MODE_OFF) {
err = adapter_ops->set_powered(adapter->dev_id, TRUE);
if (err < 0)
return err;
goto done;
}
if (adapter->up && new_mode == MODE_OFF) {
err = adapter_ops->set_powered(adapter->dev_id, FALSE);
if (err < 0)
return err;
adapter->off_requested = TRUE;
goto done;
}
if (new_mode == adapter->mode)
return 0;
//new mode 是connectable,就是hciops中的set discoverable,同時因為discoverable是false,所以,就是page scan
err = adapter_set_mode(adapter, new_mode);
done:
//新的mode 是connectable
modestr = mode2str(new_mode);
//把它寫入到config文件on mode中
write_device_mode(&adapter->bdaddr, modestr);
DBG("%s", modestr);
if (msg != NULL) {
struct session_req *req;
//用來看是否需要回給jni層內容,這裡必然有一個
req = find_session_by_msg(adapter->mode_sessions, msg);
if (req) {
adapter->pending_mode = req;
session_ref(req);
} else
/* Wait for mode change to reply */
adapter->pending_mode = create_session(adapter,
connection, msg, new_mode, NULL);
} else
/* Nothing to reply just write the new mode */
adapter->mode = new_mode;
return 0;
}
所以,這裡其實說白了就是發送了一個write scan enable的cmd,這個cmd的event我們在前文中都分析過了,會去read scan enable,然後通知上層pairable的property change。這個我們在2中進行分析。
2. 對pairable的property change的處理
同樣的,property change的處理還是在eventloop中。
[cpp]
} else if (name.equals("Pairable") || name.equals("Discoverable")) {
//設置property的值
adapterProperties.setProperty(name, propValues[1]);
if (name.equals("Discoverable")) {
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SCAN_MODE_CHANGED);
}
//得到對應的值
String pairable = name.equals("Pairable") ? propValues[1] :
adapterProperties.getProperty("Pairable");
String discoverable = name.equals("Discoverable") ? propValues[1] :
adapterProperties.getProperty("Discoverable");
// This shouldn't happen, unless Adapter Properties are null.
if (pairable == null || discoverable == null)
return;
//這裡開始的時候discoverable是false,pairable是true
int mode = BluetoothService.bluezStringToScanMode(
pairable.equals("true"),
discoverable.equals("true"));
if (mode >= 0) {
發送ACTION_SCAN_MODE_CHANGED的action
Intent intent = new Intent(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);
}
所以,對pairable這一property change的反應就是發送了ACTION_SCAN_MODE_CHANGED的action。那麼我們就來分析一下究竟有多少地方注冊了這個action的receiver。
2.1 ACTION_SCAN_MODE_CHANGED的receiver分析
注冊了這個action receiver的地方有:BluetoothDiscoverableEnabler。
2.1.1 BluetoothDiscoverableEnabler中receiver的分析
[cpp]
public void onReceive(Context context, Intent intent) {
if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
BluetoothAdapter.ERROR);
//只要不是error,就需要handle mode的changed
if (mode != BluetoothAdapter.ERROR) {
handleModeChanged(mode);
}
}
//mode changed的處理
void handleModeChanged(int mode) {
//打開的情況下,不會走到這,只有在後期設置可發現的時候,才會走到。UI上會顯示一個可發現的倒計時吧。到了那時再具體分析,其實蠻簡單的
if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
mDiscoverable = true;
updateCountdownSummary();
} else {
//這裡的話,這裡是false,這裡就是顯示兩句話:
//1)假如沒有配對設備,那麼就是顯示不讓其他藍牙設備檢測到
//2)假如已經配對了設備,那麼就是顯示只讓已配對的設備檢測到
mDiscoverable = false;
setSummaryNotDiscoverable();
}
3 powered的property change的處理
同樣的,對powered的property change的處理:
} else if (name.equals("Powered")) {
//就是發送POWER_STATE_CHANGED的msg。一看就知道是個state machine的msg,我們去看看吧 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED,
propValues[1].equals("true") ? new Boolean(true) : new Boolean(false));
此時,statemachine處於swtiching的狀態:
[cpp]
case POWER_STATE_CHANGED:
removeMessages(POWER_DOWN_TIMEOUT);
//這個if是false,我們是true,進else,我們在turnning on的狀態,所以,沒有什麼好說的。
if (!((Boolean) message.obj)) {
if (mPublicState == BluetoothAdapter.STATE_TURNING_OFF) {
transitionTo(mHotOff);
finishSwitchingOff();
if (!mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
deferMessage(obtainMessage(TURN_COLD));
}
}
} else {
if (mPublicState != BluetoothAdapter.STATE_TURNING_ON) {
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
recoverStateMachine(TURN_HOT, null);
} else {
recoverStateMachine(TURN_COLD, null);
}
}
}
break;
所以,在這裡,整個powered的change並沒有什麼特別的處理。
4、 discoverable的property change的處理
這裡discoveable是false,和上面pairable的處理時一個函數,只是多進入了一下這個函數:
[cpp]
if (name.equals("Discoverable")) {
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SCAN_MODE_CHANGED);
}
至於上層ui的改變,因為discoverable是false,所以,還是不會做什麼改變。所以就不去分析了,我們仍然只分析BluetoothAdapterStateMachine.SCAN_MODE_CHANGED這個action的處理。
同樣的,他仍然是一個adatperstatemachine的action,我們去swtiching的狀態看看他的處理。
case SCAN_MODE_CHANGED:
// This event matches mBluetoothService.switchConnectable action
if (mPublicState == BluetoothAdapter.STATE_TURNING_ON) {
// set pairable if it's not
//假如pairable不是true,就去設置pairable,因為我們已經設置了,所以這就不會有什麼了。
mBluetoothService.setPairable();
//這個函數在藍牙的狀態機裝換中已經分析過,不再詳細分析。
mBluetoothService.initBluetoothAfterTurningOn();
//轉變到buetoothon的狀態
transitionTo(mBluetoothOn);
//廣播BluetoothAdapter.ACTION_STATE_CHANGED,這次的值是STATE_ON,所以,我們還是有必要再次分析一下的。
broadcastState(BluetoothAdapter.STATE_ON);
// run bluetooth now that it's turned on
// Note runBluetooth should be called only in adapter STATE_ON
//主要就是自動連接。其它也沒有做什麼特別的,見下面的簡單分析
mBluetoothService.runBluetooth();
}
break;
/*package*/ void runBluetooth() {
//若是有可連接的設備,這裡去進行自動連接。這個這裡就不分析了
autoConnect();
// Log bluetooth on to battery stats.
//告訴電池管理那邊,藍牙打開了
long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.noteBluetoothOn();
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
我們在2.1.1中已經對BluetoothAdapter.ACTION_STATE_CHANGED這個action進行了詳細的分析。它主要就是把ui上的按鈕高亮了,其它還有一寫profile會隨著這個進行初始化,比如opp之類的,這裡等到具體分析到的時候我們再詳細的解釋吧。