Android6.0蓝牙探索旅程

来源:互联网 发布:网络缓存级别 影音先锋 编辑:程序博客网 时间:2024/06/05 19:33

废话不说,直接撸代码。
模块一:模拟手机设置界面打开蓝牙操作逐步分析。

Step1

设置界面
对应文件packages/apps/Settings/SettingsActivity.java

    private static final String[] ENTRY_FRAGMENTS = {           ......            BluetoothSettings.class.getName(),            ...... }```

蓝牙作为众多设置的一个,也被添加到数组中了。

Step2

蓝牙设置界面这里写图片描述
对应文件ackages/apps/Settings/bluetooth/BluetoothSettings.java
public class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
……….
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);
mBluetoothEnabler.setupSwitchBar();
}

}
继承自fragment,添加了一个switchBar。嗯,接下来分析BluetoothEnabler这个文件时如何来控制蓝牙的开关的。

Step3

文件目录:packages/apps/Settings/bluetooth/BluetoothEnabler.java
`public void onSwitchChanged(Switch switchView, boolean isChecked) {

    if (isChecked &&            !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {        Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();        // Reset switch to off        switchView.setChecked(false);    }    MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked);    Log.d(TAG, "mUpdateStatusOnly is " + mUpdateStatusOnly);    /// M: if receive bt status changed broadcast, do not need enable/disable bt.    if (mLocalAdapter != null && !mUpdateStatusOnly) {        mLocalAdapter.setBluetoothEnabled(isChecked);    }    mSwitch.setEnabled(false);}`

Step4

调用bluetoothAdapter的setBluetoothEnabled(isChecked)方法,
boolean success = enabled ? mAdapter.enable() : mAdapter.disable()
终于到核心类BluetoothAdapter了。
目录来了一个大的改变从packages目录到了frameworks目录。
frameworks/base/core/java/android/bluetooth/bluetoothAdapter.java

 @SystemApi    public boolean enableBLE() {        if (!isBleScanAlwaysAvailable()) return false;        if (isLeEnabled() == true) {            if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");            try {                mManagerService.updateBleAppCount(mToken, true);            } catch (RemoteException e) {                Log.e(TAG, "", e);            }            return true;        }        try {            if (DBG) Log.d(TAG, "Calling enableBLE");            mManagerService.updateBleAppCount(mToken, true);            return mManagerService.enable();        } catch (RemoteException e) {            Log.e(TAG, "", e);        }        return false;    }

Step5

重点关注 return mManagerService.enable(); mManagerService的创建时在BluetoothAdapter中完成的

  public static synchronized BluetoothAdapter getDefaultAdapter() {        if (sAdapter == null) {            IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);            if (b != null) {                IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);                sAdapter = new BluetoothAdapter(managerService);            } else {                Log.e(TAG, "Bluetooth binder is null");            }        }        return sAdapter;    }    /**     * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.     */    BluetoothAdapter(IBluetoothManager managerService) {        if (managerService == null) {            throw new IllegalArgumentException("bluetooth manager service is null");        }        try {            mService = managerService.registerAdapter(mManagerCallback);        } catch (RemoteException e) {Log.e(TAG, "", e);}        mManagerService = managerService;        mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();        mToken = new Binder();    }

我们可以看到,getDefaultAdapter方法和构造方法配合着使用。当获取实例时,mManagerService也实例化了。首先通过ServiceManager的getService返回一个binder类型的对象,然后获取到远程对象的接口managerService ,来进行远程调用。这样我们直接查看frameworks/base/core/java/android/bluetooth/BluetoothManagerService 的enable方法。

Step5

在这里前面最终还是调用了, sendEnableMsg(false);发送了MESSAGE_ENABLE消息,我们看看,哪个handler接收了这个消息。

  public boolean enable() {        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&            (!checkIfCallerIsForegroundUser())) {            Log.w(TAG,"enable(): not allowed for non-active and non system user");            return false;        }        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,                                                "Need BLUETOOTH ADMIN permission");        if (DBG) {            Log.d(TAG,"enable():  mBluetooth =" + mBluetooth +                    " mBinding = " + mBinding);        }        /// M: MoMS permission check @{        if (MobileManagerUtils.isSupported()) {            checkEnablePermission();            return true;        }        /// @}        synchronized(mReceiver) {            mQuietEnableExternal = false;            mEnableExternal = true;            // waive WRITE_SECURE_SETTINGS permission check            sendEnableMsg(false);        }        if (DBG) Log.d(TAG, "enable returning");        return true;    }   private void sendEnableMsg(boolean quietMode) {        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,                             quietMode ? 1 : 0, 0));    }

Step6

BluetoothManagerService有个内部类BluetoothHandler.java,继续发消息,里面有个doBind方法,发现最终拉起一个Service,看看ServiceConnection的onServiceConected方法,发现又是发消息MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED,里面会根据AdapterService和GattService的差异区别发送,最终传一个binder对象到message中,继续看看这个消息发送的目的地,他在BluetoothHandler中,这里也是把之前的binder对象转化成调用远程服务的接口,所以最终我们要看在
AdapterService和GattService是如何处理的。

        public void handleMessage(Message msg) {        ...          case MESSAGE_ENABLE:   mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);                    mEnable = true;                    handleEnable(msg.arg1 == 1);                    break;             case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:                {                 。。。。                    IBinder service = (IBinder) msg.obj;                    synchronized(mConnection) {                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {                   mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);                            onBluetoothGattServiceUp();                            break;                        } // else must be SERVICE_IBLUETOOTH                        //Remove timeout                      mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);                        mBinding = false;                        mBluetooth = IBluetooth.Stub.asInterface(service);                        try {                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {                                Log.e(TAG,"IBluetooth.configHciSnoopLog return false");                            }                        } catch (RemoteException e) {                            Log.e(TAG,"Unable to call configHciSnoopLog", e);                        }.....                                          break;                }                    case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:                {                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);                    synchronized(mConnection) {                        if (msg.arg1 == SERVICE_IBLUETOOTH) {                            // if service is unbinded already, do nothing and return                            if (mBluetooth == null) break;                            mBluetooth = null;                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {                            mBluetoothGatt = null;                            break;                        } else {                            Log.e(TAG, "Bad msg.arg1: " + msg.arg1);                            break;                        }                    }        ...        }            private void handleEnable(boolean quietMode) {        synchronized(mConnection) {                 if ((mBluetooth == null) && (!mBinding)) {                Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);       mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);                mConnection.setGetNameAddressOnly(false);                Intent i = new Intent(IBluetooth.class.getName());                if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,                        UserHandle.CURRENT)) {                   }    } boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);        intent.setComponent(comp);        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {            Log.e(TAG, "Fail to bind to: " + intent);            return false;        }        return true;    }  private class BluetoothServiceConnection implements ServiceConnection {。。。。。        public void onServiceConnected(ComponentName className, IBinder service) {            if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {                msg.arg1 = SERVICE_IBLUETOOTH;                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {                msg.arg1 = SERVICE_IBLUETOOTHGATT;            } else {                Log.e(TAG, "Unknown service connected: " + className.getClassName());                return;            }            msg.obj = service;            mHandler.sendMessage(msg);        }        。。。。    }

Step7

上面已经说到,要找AdapterService和GattService里继续追踪。接下来重点考虑AdapterService,他的路径在Packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService,所以又从framework层调到了app层。从何处入手了,Step6中说了拉起服务的事,其实后面拉起服务后还会有一段代码,启动蓝牙,我们看看AdapterService的enable方法。

                //Enable bluetooth                try {                    if (!mQuietEnable) {                        if(!mBluetooth.enable()) {                            Log.e(TAG,"IBluetooth.enable() returned false");                        }                    }                    else {                        if(!mBluetooth.enableNoAutoConnect()) {                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");                        }                    }                } catch (RemoteException e) {                    Log.e(TAG,"Unable to call enable()",e);                }public class AdapterService extends Service {...public synchronized boolean enable(boolean quietMode) {         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");         debugLog("enable() - Enable called with quiet mode status =  " + mQuietmode);         mQuietmode = quietMode;         Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_ON);         mAdapterStateMachine.sendMessage(m);         return true;     }     ...     }

Step8

嗯,继续发消息,AdapterState.BLE_TURN_ON
Packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterState.java,里面有很多stateMachine,也有对消息的监听这里,我也有点蒙圈,不按照套路出牌,最终要调用adapterService.enableNative()的native方法,进行jni通信。

 case BLE_TURN_ON:                    if (isTurningOff || isBleTurningOff) {                        infoLog("Deferring BLE_TURN_ON request...");                        deferMessage(msg);                    }                    break;  case BLE_STARTED:                    //Remove start timeout                    removeMessages(BLE_START_TIMEOUT);                    //Enable                    if (!adapterService.enableNative()) {                        errorLog("Error while turning Bluetooth on");                        notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);                        transitionTo(mOffState);                    } else {                        sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);                    }                    break;

Step9

从应用层调到了蓝牙协议栈了,我们看看它的c++层是如何操作的。
Packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp,蓝牙驱动对象sBluetoothInterface的enable方法。好吧我再也分析不下去了。

static jboolean enableNative(JNIEnv* env, jobject obj) {          ALOGV("%s:",__FUNCTION__);          jboolean result = JNI_FALSE;          if (!sBluetoothInterface) return result;          int ret = sBluetoothInterface->enable();          result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;          return result;      }  

总的来说博通写的蓝牙模块的内容涉及了好多message信息的处理。下面一篇我会对蓝牙文件传输进行分析。

0 0