android 4.0 藍芽分析之一
Code:
// Skip Bluetooth if we have an emulator kernel
223 // TODO: Use a more reliable check to see if this product should
224 // support Bluetooth - see bug 988521
225 if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
226 Slog.i(TAG, "No Bluetooh Service (emulator)");
227 } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
228 Slog.i(TAG, "No Bluetooth Service (factory test)");
229 } else {
230 Slog.i(TAG, "Bluetooth Service");
231 bluetooth = new BluetoothService(context);
232 ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);
233 bluetooth.initAfterRegistration();
234 bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
235 ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
236 bluetoothA2dp);
237 bluetooth.initAfterA2dpRegistration();
238
239 int airplaneModeOn = Settings.System.getInt(mContentResolver,
240 Settings.System.AIRPLANE_MODE_ON, 0);
241 int bluetoothOn = Settings.Secure.getInt(mContentResolver,
242 Settings.Secure.BLUETOOTH_ON, 0);
243 if (airplaneModeOn == 0 && bluetoothOn != 0) {
244 bluetooth.enable();
245 }
246 }
SystemServer.Java 裡,在addService()時
bluetooth = new BluetoothService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);
bluetooth.initAfterRegistration();
bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
bluetooth.initAfterA2dpRegistration();
addService後,執行了紅色initAfterRegistration()方法,該方法裡傳送了一個訊息
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT),進入BluetoothAdapterStateMachine之後,TURN_HOT的處理有兩處,到底是哪一處的處理呢,我們到BluetoothAdapterStateMachine的建構函式裡去看,在BluetoothAdapterStateMachine的建構函式裡,設定了初始化狀態為setInitialState(mPowerOff);因此addService後的TURN_HOT,
進入的是PowerOff裡的TURN_HOT。
1.1 藍芽的狀態
藍芽狀態如下:
· Power off
這就是藍芽模組沒有初始化的狀態,這時候硬體模組是出於沒有上電的狀態。
· Warm up
這個狀態就是給裝置上電,使裝置能夠從沒電到待機狀態。
· Hot off
Hot off我個人理解就是在模組上電了,出於一種待命的狀態,如果收到了turn_on_coninue的命令時候就會去將藍芽模組切換到工作狀態。如果接收到了turn_cold的命令時候,裝置就會斷電進入power off狀態。
· Switching
這也是一箇中間狀態,需要繼續接收命令。
· Bluetooth on
這時藍芽模組出於正常工作的狀態。
1.2 藍芽的使能
在上層應用中,藍芽介面類是BluetoothSettins.java,在actionBar上還有一個開關,另外MENU裡也有四個選單項。
實現藍芽開關邏輯處理的類是BluetoothEnabler.java,當我們開啟或關閉開關時,會執行onCheckedChanged()方法,
if (mLocalAdapter != null) {
mLocalAdapter.setBluetoothEnabled(isChecked);
}
這裡,LocalBluetoothAdapter的setBluetoothEnabled方法,然後呼叫了BluetoothAdapter.java的 enable(), 進而呼叫到了IBluetooth的 enable(),這裡的IBluetooth對應的有一個IBluetooth.aidl,
由此可以知道,是通過程式間通訊,呼叫到了BluetoothService.java裡的enable(),BluetoothService.java裡的enable()裡,我們很高興看到如下程式碼:
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting);
這裡就是傳送了一個USER_TURN_ON訊息,而處理該訊息的地方是在processMessage()裡,然後再根據狀態,確認是在哪個狀態對該訊息進行了處理,processMessage()對該訊息的處理如下:
Code:
case USER_TURN_ON:
// starts turning on BT module, broadcast this out
broadcastState(BluetoothAdapter.STATE_TURNING_ON);
transitionTo(mWarmUp);
if (prepareBluetooth()) {
// this is user request, save the setting
if ((Boolean) message.obj) {
persistSwitchSetting(true);
}
// We will continue turn the BT on all the way to the BluetoothOn state
deferMessage(obtainMessage(TURN_ON_CONTINUE));
} else {
Log.e(TAG, "failed to prepare bluetooth, abort turning on");
transitionTo(mPowerOff);
broadcastState(BluetoothAdapter.STATE_OFF);
}
break;
上一小節中講到的藍芽的狀態,透過程式碼可以看到,是通過transitionTo()方法來切換藍芽的狀態的。
1.3 呼叫流程
方法呼叫流程如下:
BluetoothSetting.java ------>
BluetoothEnable.java( onCheckedChanged() ) ------>
LocalBlutoothAdapter.java ( setBluetoothEnable() ) ------>
BluetoothAdapter.java( enable()) ------>
IBluetooth.aidl( enable() ) ------>
BluetoothService.java( enable() ) ------>
BluetoothAdapterStateMachine.java( enableNative() ) ------>
android_server_BluetoothService.cpp
2. 藍芽的掃描
2.1 藍芽掃描
藍芽掃描的流程,結構比較清晰,根據程式碼,分析打描的流程如下:
上層應用層程式碼呼叫startScanning()方法,這個方法會LocalBluetoothAdapter.java的startScanning()方法,進而呼叫到framework裡的BluetoothAdapter.java裡,關於這點,是和開啟藍芽的流程是一致的,需要說有的是,呼叫LocalBluetoothAdapter.java裡面的方法,最終都是呼叫到了BluetoothAdapter.java裡,後面有其它類似的方法也是如此。
在BluetoothAdapter.java裡,則是startDiscovery()方法來掃描藍芽裝置的,使用的也是IBluetooth.aidl的檔案來實現程式間通訊,進而呼叫到BluetoothService.java裡的startDiscovery(),到了這裡,之後就是本地方法startDiscoveryNative()了,本地方法呼叫到了android_server_BluetoothService.cpp裡。
2.2 呼叫流程
方法呼叫流程如下:
BluetoothSetting.java ------>
LocalBlutoothAdapter.java (startScanning () ) ------>
BluetoothAdapter.java(startDiscovery ()) ------>
IBluetooth.aidl(startDiscovery () ) ------>
BluetoothService.java(startDiscovery () ) ------>
BluetoothAdapterStateMachine.java(startDiscoveryNative () ) ------>
android_server_BluetoothService.cpp
2.3 掃描結果
當掃描到了裝置時,在android_server_BluetoothEventLoop.cpp裡有一個方法:
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
void *data)
這個方法裡各種事件的處理,其中掃描到藍芽裝置後的處理是
Code:
if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
"DeviceFound")) {
char *c_address;
DBusMessageIter iter;
jobjectArray str_array = NULL;
if (dbus_message_iter_init(msg, &iter)) {
dbus_message_iter_get_basic(&iter, &c_address);
if (dbus_message_iter_next(&iter))
str_array =
parse_remote_device_properties(env, &iter);
}
if (str_array != NULL) {
env->CallVoidMethod(nat->me,
method_onDeviceFound,
env->NewStringUTF(c_address),
str_array);
} else
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
goto success;
}
這裡會有一個標識“DeviceFound”,呼叫到方法則是 method_onDeviceFound,接下來的處理是
method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
"(Ljava/lang/String;[Ljava/lang/String;)V");
這樣,通過JNI, C++的方法調到了上層java程式碼中的BluetoothEventLoop.java的方法onDeviceFound()中,最終呼叫addDevice(),從而新增一個掃描到的藍芽裝置,並最終新增到BluetoothDeviceProperties.java中去了。
Code:
private void addDevice(String address, String[] properties) {
BluetoothDeviceProperties deviceProperties =
mBluetoothService.getDeviceProperties();
deviceProperties.addProperties(address, properties);
……
}
2.4 程式間通訊
掃描和使能在BluetoothAdapter.java中,在呼叫enable()和startDiscovery()時,都呼叫到了IBluetooth.aidl中,在Android中,. aidl是用於程式間通訊的。
AIDL程式間通訊,在BluetoothAdapter.java裡,enable()方法如下:
Code:
public boolean enable() {
try {
return mService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
這裡,我們發現IBluetooth service = IBluetooth.Stub.asInterface(b),在frameworks\base\core\java\android\bluetooth目錄下,有一個IBluetooth.aidl,這裡是用到了程式間通訊,在android裡,程式間通訊常用aidl來實現,最終IBluetooth呼叫到了哪個地方,我們看下IBluetooth的實現, BluetoothService最終實現了IBluetooth(BluetoothService extends IBluetooth.Stub),因此呼叫enable方法是呼叫這裡的enable()方法。
3. 藍芽的配對與連線
3.1 藍芽的配對
3.1.1 master
掃描到可用的藍芽裝置後,在BluetoothDevicePreference.java裡,點選列表中的某一藍芽裝置,會根據各個裝置的bondState,會有不同的流程:
Code:
int bondState = mCachedDevice.getBondState();
if (mCachedDevice.isConnected()) {
askDisconnect();
} else if (bondState == BluetoothDevice.BOND_BONDED) {
mCachedDevice.connect(true);
} else if (bondState == BluetoothDevice.BOND_NONE) {
pair();
}
即如果已邊接,則會斷開邊接disconnect(profile),如果狀態是已配對,則會去連線connect(true),如果狀態是NONE,則會先配對pair()。這裡配對和連線需要注意的是,
都會進入startPairing(),進一步進入呼叫到BluetoothServcie.java裡的createBond();
這裡做所的工作就是配對。
3.1.2 slave
被要求配對的一方,在BluetoothPairingRequest.java這個廣播裡,會接收到來自底層的一個配對請求,接收到BluetoothDevice.ACTION_PAIRING_REQUEST的ACTION,並彈出提示框(BluetoothPairingDialog.java),提示使用者配對。
3.1.3 取消配對
在DeviceProfilesSettings.java中,取消配對直接呼叫unpairDevice,最終會呼叫到CachedBluetoothDevice.java的unpair()方法,取消配對時,會直接斷開連線了,呼叫disconnect(),取消配對時,也會根據狀態,分別做不同的處理
Code:
int state = getBondState();
if (state == BluetoothDevice.BOND_BONDING) {
mDevice.cancelBondProcess();
}
if (state != BluetoothDevice.BOND_NONE) {
final BluetoothDevice dev = mDevice;
if (dev != null) {
final boolean successful = dev.removeBond();
if (successful) {
if (Utils.D) {
Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
}
} else if (Utils.V) {
Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
describe(null));
}
}
}
3.2 藍芽的連線
配對後即可進行A2DP, FTP等操作,不同的業務,都會走各自的連線,如BluetoothHeadset.java/BluetoothA2dp.java都有各自的connect()方法,待後續各自的profile裡,單獨分析各自的連線功能。
3.3 相關的介面類:
BluetoothSettings.java
DeviceListPreferenceFragment.java
BluetoothPairingDialog.java
4. 重新命名藍芽裝置
4.1 呼叫流程
重新命名藍芽裝置是一個從上到下單線的流程,在BluetoothNameDialogFragment.java這個dialog裡,直接呼叫setName(),一直往下調到BluetoothAdapter.java裡的setName()裡。
5. 藍芽可見時間
5.1 呼叫流程
可被檢測到的主要邏輯處理在BluetoothDiscoverableEnabler.java裡,這個流程較為簡單,直接在BluetoothDiscoverableEnabler.java這個類裡呼叫setEnable(),然後一步一步呼叫到BluetoothAdapter.java裡的mService.setDiscoverableTimeout(timeout),進而呼叫到BluetoothService.java裡的setDiscoverableTimeout()。
6. 接收到的檔案
6.1 呼叫流程
當使用者點選“接收到的檔案”選單時,會直接傳送一個廣播
Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
getActivity().sendBroadcast(intent);
這個廣播將會被BluetoothOppReceiver.java接收到,進一步跳轉到BluetoothOppTransferHistory.java中,列出所有接收到的檔案。
Intent in = new Intent(context, BluetoothOppTransferHistory.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
in.putExtra("direction", BluetoothShare.DIRECTION_INBOUND);
in.putExtra(Constants.EXTRA_SHOW_ALL_FILES, true);
context.startActivity(in);
接收到的檔案功能實現是OPP裡實現的,具體在OPP的分析中,會有進一步詳細的分析。
7. 介面
藍芽設定只有兩個介面,其他的都是一些 dialog ,menu.。
7.1 藍芽設定介面
進入藍芽設定的介面:BluetoothSettings.java
已配對的藍芽,進入後,可進行重新命名,取消配對的介面:DeviceProfilesSettings
相關文章
- Android藍芽使用詳解(普通藍芽)Android藍芽
- React Native 藍芽4.0 BLE開發React Native藍芽
- iOS 藍芽4.0開發使用(內附Demo)iOS藍芽
- Android Ble藍芽入門Android藍芽
- Android開發--藍芽操作Android藍芽
- Android-藍芽聊天demoAndroid藍芽
- Android 傳統藍芽開發Android藍芽
- android藍芽BLE(一) —— 掃描Android藍芽
- android藍芽BLE(三) —— 廣播Android藍芽
- android藍芽BLE(二) —— 通訊Android藍芽
- Android藍芽子系統"BlueFrag"漏洞分析(CVE-2020-0022)Android藍芽
- 藍芽4.0技術知識整理和基本介紹藍芽
- Android藍芽開發流程實踐Android藍芽
- Android BLE藍芽詳細解讀Android藍芽
- Android Studio 藍芽 示例程式碼(轉)Android藍芽
- Android藍芽讀取簡訊調研Android藍芽
- Android:藍芽實現一對一聊天Android藍芽
- 手機藍芽硬體APP公司分析藍芽自動重連機制藍芽APP
- 藍芽藍芽
- 深入瞭解Android藍芽Bluetooth——《基礎篇》Android藍芽
- iOS藍芽開發 Bluetooth藍芽CoreBluetooth 藍芽中心裝置的實現 藍芽外設的實現 有DemoiOS藍芽
- Android BLE 藍芽開發——掃碼槍基於BLESSEDAndroid藍芽
- ESP32藍芽學習--藍芽概念學習藍芽
- java+藍芽Java藍芽
- 藍芽模組藍芽模組
- MASA MAUI Plugin IOS藍芽低功耗(三)藍芽掃描UIPluginiOS藍芽
- SKYLAB:藍芽閘道器應用場景案例分析藍芽
- MASA MAUI Plugin 安卓藍芽低功耗(一)藍芽掃描UIPlugin安卓藍芽
- 智慧裝置端與 APP 之間如何實現自動化測試 (藍芽 4.0)APP藍芽
- iOS藍芽開發iOS藍芽
- 白色藍芽耳機藍芽
- BLE低功耗藍芽藍芽
- 藍芽解鎖AutoLock 1.0.2 Mac中文版 (藍芽WiFi解鎖工具)藍芽MacWiFi
- 藍芽共享網路怎麼用 win10藍芽共享網路藍芽Win10
- 電腦藍芽怎麼連線 電腦連線藍芽的方法藍芽
- 藍芽韌體升級藍芽
- 藍芽Beacon格式詳解藍芽
- android 藍芽耳機雜音和耳機相容性問題是什麼原因?如何分析和解決?Android藍芽
- 怎麼更新電腦藍芽驅動 win10藍芽驅動更新藍芽Win10