allwinner4.0.4:
SystemServer.java:
if (SystemProperties.get("ro.kernel.qemu").equals("1") || SystemProperties.get("ro.bluetooth.disable").equals("1")) { Slog.i(TAG, "No Bluetooh Service (emulator)"); } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) { Slog.i(TAG, "No Bluetooth Service (factory test)"); } else { Slog.i(TAG, "Bluetooth Service"); bluetooth = new BluetoothService(context); ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth); bluetooth.initAfterRegistration(); bluetoothA2dp = new BluetoothA2dpService(context, bluetooth); ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE, bluetoothA2dp); bluetooth.initAfterA2dpRegistration(); int airplaneModeOn = Settings.System.getInt(mContentResolver, Settings.System.AIRPLANE_MODE_ON, 0); int bluetoothOn = Settings.Secure.getInt(mContentResolver, Settings.Secure.BLUETOOTH_ON, 0); if (airplaneModeOn == 0 && bluetoothOn != 0) { bluetooth.enable(); } }
首先ro.kernel.qemu判斷是不是模擬器啟動,如果不是,採取啟動藍芽服務,否則略過;接著如果bluetoothOn不為0,則bluetooth.enable()開機預設開啟藍芽
跟進去看看bluetooth.enable()的操作,在BluetoothService.java中:
public synchronized boolean enable(boolean saveSetting) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); // Airplane mode can prevent Bluetooth radio from being turned on. if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { return false; } mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting); return true; }
先判斷許可權和飛航模式,最後發送訊息USER_TURN_ON,表示要開啟藍芽了mBluetoothState是一個狀態機器,所以進入BluetoothAdapterStateMachine.java中。
初始化時候狀態是在PowerOff,所以進入PowerOff中:
private class PowerOff extends State { @Override public void enter() { if (DBG) log("Enter PowerOff: " + getCurrentMessage().what); } @Override public boolean processMessage(Message message) { log("PowerOff process message: " + message.what); boolean retValue = HANDLED; switch(message.what) { 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; ..................................... }
可以看到,藍芽狀態機器接收到USER_TURN_ON後,首先廣播藍芽適配器處於STATE_TURNING_ON狀態,藍芽適配器狀態有四種:
state_off(10),state_turning_on(11),state_on(12),state_turning_off(14)
接下來看prepareBluetooth()函數:
private boolean prepareBluetooth() { if (mBluetoothService.enableNative() != 0) { return false; } // try to start event loop, give 2 attempts int retryCount = 2; boolean eventLoopStarted = false; while ((retryCount-- > 0) && !eventLoopStarted) { mEventLoop.start(); // it may take a moment for the other 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; } ............................. }
mBluetoothService.enableNative()調用了BluetoothService的enableNative,也就是JNI方法了,所以進入android_server_BluetoothService.cpp中:
static jint enableNative(JNIEnv *env, jobject object) {#ifdef HAVE_BLUETOOTH LOGV("%s", __FUNCTION__); return bt_enable(); #endif return -1;}
bt_enable調用的是system/bluetooth/bluedroid/bluetooth.c的函數:
int bt_enable() { LOGV(__FUNCTION__); int ret = -1; int hci_sock = -1; int attempt; LOGI("bt_enable()");#ifndef BOARD_HAVE_BLUETOOTH_CSR //if (set_bluetooth_power(1) < 0) goto out; #else LOGI("Starting bccmd command"); if (property_set("ctl.start", "bccmd") < 0) { LOGE("Fail to bccmd"); goto out; } sleep(5);#endif#if defined(SW_BOARD_HAVE_BLUETOOTH_RTK) usleep(1000000); // 1 seconds#endif LOGI("Starting hciattach daemon"); if (property_set("ctl.start", "hciattach") < 0) { LOGE("Failed to start hciattach");#ifndef BOARD_HAVE_BLUETOOTH_CSR //set_bluetooth_power(0);#endif goto out; } // Try for 10 seconds, this can only succeed once hciattach has sent the // firmware and then turned on hci device via HCIUARTSETPROTO ioctl for (attempt = 1000; attempt > 0; attempt--) { hci_sock = create_hci_sock(); if (hci_sock < 0) goto out; 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 already started, unexpectedly!"); break; } close(hci_sock); usleep(100000); // 100 ms retry delay } if (attempt == 0) { LOGE("%s: Timeout waiting for HCI device to come up, error- %d, ", __FUNCTION__, ret); if (property_set("ctl.stop", "hciattach") < 0) { LOGE("Error stopping hciattach"); }#ifndef BOARD_HAVE_BLUETOOTH_CSR //set_bluetooth_power(0);#endif goto out; } LOGI("Starting bluetoothd deamon"); if (property_set("ctl.start", "bluetoothd") < 0) { LOGE("Failed to start bluetoothd");#ifndef BOARD_HAVE_BLUETOOTH_CSR //set_bluetooth_power(0);#endif goto out; }#ifdef BOARD_HAVE_BLUETOOTH_CSR if (property_set("ctl.start", BTFILTER_NAME) < 0) { LOGE("Failed to start abtfilt"); goto out; } usleep(1000);#endif ret = 0;out: if (hci_sock >= 0) close(hci_sock); return ret;}
這裡set_bluetooth_power會讀取藍芽的硬體狀態,如果為on的話才開啟藍芽,怎麼說呢?也就是藍芽的HCI驅動註冊的時候會註冊一個rfkill,以一個裝置節點的形式呈現給上層,它指示著電源的狀態,比如我們在電腦鍵盤上面可能會看見一個按鍵來開關藍芽或者wifi之類的。這裡會去讀這個索引值,如果是1代表可以開啟藍芽的,否則是沒法使用藍芽的。我們這裡沒有這樣的索引值,所以將它屏蔽掉。
接著property_set("ctl.start", "hciattach")啟動HCI服務,然後create_hci_sock來建立socket,這樣就可以和HCI服務通訊了
接下來ioctl,參數是HCIDEVUP,就進入了驅動linux-3.0/net/bluetooth/hci_sock.c中:
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ ................................. case HCIDEVUP: if (!capable(CAP_NET_ADMIN)) return -EACCES; return hci_dev_open(arg); .....................................}
調用hci_dev_open(arg), 這個函數的效果就好比我們在終端下面使用藍芽調試工具hciconfig
int hci_dev_open(__u16 dev) { struct hci_dev *hdev; int ret = 0; hdev = hci_dev_get(dev); if (!hdev) return -ENODEV; ............................. if (hdev->open(hdev)) { ret = -EIO; goto done; } .....................................}
這裡得到一個hci_dev裝置,然後調用他的open,其實就是我們註冊藍牙堆疊時候的回呼函數,會調用我們藍牙堆疊的open
mBluetoothService在enableNative()函數主要功能就是通過一系列代碼來開啟藍牙裝置。如果裝置驅動代碼沒有問題的話,我們enableNative()返回的將會是true。在實際調試藍牙裝置時候,我們可以通過在linux或者android的終端下面使用內建的工具命令(hciconfig),執行:
# hciconfig –a如果驅動能夠和裝置綁定的話,我們就會看到藍牙裝置的一些比較重要訊息,如:藍芽的物理地址,匯流排類型,協議類型等
回到藍芽狀態機器的prepareBluetooth函數中,接著執行mEventLoop.start(),所以進入BluetoothEventLoop.java中:
/* package */ void start() { if (!isEventLoopRunningNative()) { if (DBG) log("Starting Event Loop thread"); startEventLoopNative(); } }
startEventLoopNative是JNI方法:
這裡的函數很長,主要是建立socket,建立一個專門讀取資料的線程,將bluz掛在dbus上,最後一輪詢的方式讀取資料,有資料來了的話根據資料的類型做相應的處理
分析完prepareBluetooth,如果沒有問題,就用persistSwitchSetting將狀態Settings.Secure.BLUETOOTH_ON寫到資料庫中儲存起來
狀態機器在前面transitionTo(mWarmUp),已經切換到了mWarmUp模式,並且發送了deferMessage(obtainMessage(TURN_ON_CONTINUE)),所以進入WarmUp狀態:
未完,參考http://www.cnblogs.com/chenbin7/archive/2012/09/05/2670652.html