原址
SystemServer启动开始讲起,在SystemServer启动的时,会启动一个BluetoothService与BluetoothA2DPService的实例:

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

DeviceProfilesSettings.java

BluetoothPairingRequest.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 4.0 蓝牙分析之一相关推荐

  1. android 4.0 蓝牙分析之二

    原址 packages/apps/Settings/src/com/Android/settings/bluetooth/BluetoothSettings.Java onCreateOptionsM ...

  2. aptx android8,秒杀苹果无线音频!Android 8.0蓝牙音质支持aptxHD/LDAC

    原标题:秒杀苹果无线音频!Android 8.0蓝牙音质支持aptxHD/LDAC [TechWeb报道]8月25日消息,本周将迎来Android 8.0"奥利奥"系统推送,目前已 ...

  3. Android 9.0 蓝牙功能之一:蓝牙音乐

    Android 9.0 蓝牙功能之一:蓝牙音乐 本章节记录如何构建蓝牙音乐. 文章目录 Android 9.0 蓝牙功能之一:蓝牙音乐 主要流程 相关代码 其他要点: 蓝牙AG_EVENT广播 (手机 ...

  4. android 6.0蓝牙服务开启,Android应用开发之Android 6.0 蓝牙搜索不到设备原因,MIUI权限申请机制方法...

    本文将带你了解Android应用开发Android 6.0 蓝牙搜索不到设备原因,MIUI权限申请机制方法,希望本文对大家学Android有所帮助. 为提供更高的数据保护   Android6.0版本 ...

  5. android 6.0 蓝牙进程,Android6.0-蓝牙权限问题

    在Android 6.0,原来的蓝牙功能,发现扫描蓝牙设备时,无法获取到蓝牙设备:因为在6.0后,蓝牙这块增加一个动态权限:需要在程序中动态申请. 1)        在6.0版本前,使用蓝牙功能,只 ...

  6. Android 8.0 蓝牙唤醒 Ble 锁屏 保活 后台 持续扫描 进程拉活 自动唤醒

    主要是api的说明,嫌啰嗦的可以直接看demo,demo中有个检测锁屏时间重复开启扫描的代码,主要是如果APP没有获得电量或者后台运行的权限,只能持续后台运行几小时. 这个demo的作用是实现8.0以 ...

  7. android Ble4.0蓝牙开发之搜索慢、startLeScan()过时,6.0以上不需要定位权限也能快速搜索到蓝牙设备

    项目中需要用到android Ble蓝牙4.0开发技术,于是开启了蓝牙填坑之旅,说实话,蓝牙开发坑真多,跳出一个又进入下一个,每次遇到 问题,就觉得不可能解决了,还好在自己的摸索中,都一一的化解了,以 ...

  8. android 6.0蓝牙,Android 6.0 蓝牙搜索不到设备原因,MIUI权限申请机制方法

    为提供更高的数据保护 Android6.0版本上增加了关于Wifi和蓝牙的权限. 蓝牙搜索到设备需要用到定位服务,所以在开发中 targetSdkVersion 大于等于23(6.0) 需要在代码中进 ...

  9. Android 9.0 蓝牙通讯录 BluetoothPbapClient

    蓝牙通讯录主要包含联系人和通话记录 一.BluetoothPbapClient功能介绍 1.主要实现电话簿下载 2.电话号码簿访问协议(Phonebook Access Profile) 二.Blue ...

最新文章

  1. ios9定位服务的app进入后台三分钟收不到经纬度,应用被挂起问题及解决方案
  2. SQL SERVER特殊行转列案列一则
  3. 动态规划 4、基础背包问题总结(多重背包与多重背包的转化)
  4. ansys如何删除线_ANSYS影响面计算与绘制方法介绍
  5. SpringMVC的环境搭建
  6. Android -- 再来一发Intent
  7. webdriver 爬虫 java_java爬虫通过selenium+WebDriver遍历页面链接报错
  8. C++(STL):14--- forward_list比list更高效的容器
  9. android 图片 切换,Android 应用开发笔记 - 切换图片(ImageSwitcher)
  10. 通过设置代理解决AndroidStudio无法下载gradle问题
  11. java基础-(一)-JDK的下载和安装
  12. 安卓rom制作教程_OPPO Reno安卓9系统如何升级ColorOS6.7最新版本-安卓10系统
  13. 需要编程资料(java、php、python、js、vue)、SS账号、或者mac破解软件的戳
  14. 威洛特:你的猫有以下6种情形 ,便知把你当父母还是孩子
  15. 【电力电子】【2013】基于对称分量提取的三电平三相并网变流器电压暂降时的电网同步与控制
  16. java构造方法中this_Java中this关键字在构造方法中的使用
  17. Android中具有动画效果的图片资源
  18. 蛙蛙推荐:蛙蛙牌关键词提取算法
  19. c语言99乘法口诀金字塔,作业:金字塔、乘法口诀表和字符反输出
  20. 白苹果了怎么办_苹果手机数据恢复真的能行吗?

热门文章

  1. 通过python切换hosts文件
  2. Javascript之旅——第十站:为什么都说闭包难理解呢?
  3. 《变革中的思索》连载九:放飞的爱——母亲和我
  4. PHP error_reporting的使用
  5. Django笔记7(通用视图)
  6. Grafana 系统可视化监控
  7. Android 与 JavaScript 相互调用桥梁 JSBridge
  8. A - A Dangerous Maze
  9. linux下c++版本线程池的实现
  10. 一个按钮控制暂停和开始java_《第一炉香》|一个女人的自甘堕落,从控制不住欲望开始...