BluetoothEnabler.java +187
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Show toast message if Bluetooth is not allowed in airplane mode
if (isChecked &&
!WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off
buttonView.setChecked(false);
}
if (mLocalAdapter != null) {
mLocalAdapter.setBluetoothEnabled(isChecked);
}
mSwitch.setEnabled(false);
}
继续看setBluetoothEnabled()方法做什么了,很明显mLocalAdapter(LocalBluetoothAdapter )只是个过渡,里面的 mAdapter(BluetoothAdapter)才是真正的主角
LocalBluetoothAdapter.java +205
public void setBluetoothEnabled(boolean enabled) {
boolean success = enabled ? mAdapter.enable() : mAdapter.disable();
if (success) {
setBluetoothStateInt(enabled
? BluetoothAdapter.STATE_TURNING_ON
: BluetoothAdapter.STATE_TURNING_OFF);
} else {
.........
}
}
在BluetoothAdapter.java里可以看到一个单例模式的应用,主要提供给其它程序调用蓝牙的一些方法用的,外部程序想调用蓝牙的方法就要先用这个。再继续追就是frameworks层,底层如何实现打开蓝牙的过程,我们在这这个方向不研究。
触发蓝牙搜索的条件形式上有两种,一是在蓝牙设置界面开启蓝牙会直接开始搜索,另一个是先打开蓝牙开关在进入蓝牙设置界面也会触发搜索,也可能还有其它触发方式,但最后都要来到BluetoothSettngs.java的startScanning(),我们分析的起点也从这里开始,起步代码如下
BluetoothSettings.java +282
switch (bluetoothState) { case BluetoothAdapter.STATE_ON:
............
if (!mInitialScanStarted) {
startScanning();
}
...........
private void startScanning() {
...........
mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
258 mAvailableDevicesCategory.removeAll();
259 mInitialScanStarted = true;
260 mLocalAdapter.startScanning(true); //!!!!!
262 }
其实在这里蓝牙搜索和打开流程是结构上是一致的,利用LocalBluetoothAdapter.java过渡到BluetoothAdapter.java再跳转至AdapterService.java要稍微留意下的是在这个过渡中startScaning()方法变成了startDiscovery()方法,看下代码:
LocalBluetoothAdapter.java +141
void startScanning(boolean force) {
if (!mAdapter.isDiscovering()) {
if (!force) {
// Don't scan more than frequently than SCAN_EXPIRATION_MS,
// unless forced
if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
return;
}
// If we are playing music, don't scan unless forced.
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
}
//这里才是我们最关注的,前面限制条件关注一下就行了
if (mAdapter.startDiscovery()) {
mLastScan = System.currentTimeMillis();
}
}
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java +746
public boolean startDiscovery() {
.............................
AdapterService service = getService();
if (service == null) return false;
return service.startDiscovery();
}
BluetoothAdapter.java的那一段,路径 /frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java +840
840 public boolean startDiscovery() {
...
843 synchronized(mManagerCallback) {
844 if (mService != null)
return mService.startDiscovery(); !!!!!
845 }
846 .....
848 }
1221 boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
return startDiscoveryNative();
}
这个service代码写得很明白AdapterService,转了一圈从framework又回到packages了。
和打开蓝牙根本就是一个套路,上面的流程略过一小步,很简单的不写了,下面要怎么走,估计大家也都猜到了,JNI应该出场了,
路径:/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp +820
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;
int ret = sBluetoothInterface->start_discovery();
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
路径:/external/bluetooth/bluedroid/btif/src/bluetooth.c +250
static int start_discovery(void)
{
/* sanity check */
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;
return btif_dm_start_discovery();
}
下面代码直接跳转就可以找到,路径external/bluetooth/bluedroid/btif/src/btif_dm.c +2148
bt_status_t btif_dm_start_discovery(void)
{
tBTA_DM_INQ inq_params;
tBTA_SERVICE_MASK services = 0;
BTIF_TRACE_EVENT1("%s", __FUNCTION__);
/* TODO: Do we need to handle multiple inquiries at the same time? */
/* Set inquiry params and call API */
#if (BLE_INCLUDED == TRUE)
inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
#else
inq_params.mode = BTA_DM_GENERAL_INQUIRY;
#endif
inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
inq_params.report_dup = TRUE;
inq_params.filter_type = BTA_DM_INQ_CLR;
/* TODO: Filter device by BDA needs to be implemented here */
/* Will be enabled to TRUE once inquiry busy level has been received */
btif_dm_inquiry_in_progress = FALSE;
/* find nearby devices */ BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
return BT_STATUS_SUCCESS;
}
BTA_DmSearch()方法是看起来是要搜索了,不过里面这个家伙bte_search_devices_evt才是真正干活的主力,所以我们先看它,在这个函数里
static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) {
UINT16 param_len = 0;
if (p_data)
param_len += sizeof(tBTA_DM_SEARCH);
/* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
switch (event)
{
case BTA_DM_INQ_RES_EVT:
{
if (p_data->inq_res.p_eir)
param_len += HCI_EXT_INQ_RESPONSE_LEN;
}
break;
..............................
}
BTIF_TRACE_DEBUG3("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
/* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
if (event == BTA_DM_INQ_RES_EVT)
p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
}
上面的这个函数里又有这个bte_search_devices_evt,在它里我们能看一个 HAL_CBACK,这是要往回发消息了,看下这个函数的全貌,说是全貌,不过还是只贴出一个case分支,太长了,大家还是自行还源码吧。到这里已经可以知道扫描到蓝牙设备的mac地址和设备名,那个bdcpy函数就是在解析mac地址,有了这些,蓝牙搜索是到应该在界面展示成果的时候了,开始回调。
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
tBTA_DM_SEARCH *p_search_data;
BTIF_TRACE_EVENT2("%s event=%s", __FUNCTION__, dump_dm_search_event(event));
switch (event)
{
case BTA_DM_DISC_RES_EVT:
{
p_search_data = (tBTA_DM_SEARCH *)p_param;
/* Remote name update */
if (strlen((const char *) p_search_data->disc_res.bd_name))
{
bt_property_t properties[1];
bt_bdaddr_t bdaddr;
bt_status_t status;
properties[0].type = BT_PROPERTY_BDNAME;
properties[0].val = p_search_data->disc_res.bd_name;
properties[0].len = strlen((char *)p_search_data->disc_res.bd_name);
bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
status, &bdaddr, 1, properties);
}
/* TODO: Services? */
}
break;
当然回过头我们还要看下那个BTA_DmSearch(),看它的实现,更应该是起消息发送的作用,代码在/external/bluetooth/bluedroid/bta/dm/bta_dm_api.c, +2196 这个函数具体流程并没有看多少,当工具方法看了,有时间看看还是没坏处的。
void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{ tBTA_DM_API_SEARCH *p_msg;
if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
{
memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));
p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
p_msg->services = services;
p_msg->p_cback = p_cback;
p_msg->rs_res = BTA_DM_RS_NONE;
bta_sys_sendmsg(p_msg);
}
}
看了上面方法后我们 要回去了看看,代码通过JNI下来的,回去也是看JNI的回调方法,packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp +698
method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
deviceFoundCallback方法最后会来java层的 /packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java +327
void deviceFoundCallback(byte[] address) {
// The device properties are already registered - we can send the intent
// now
BluetoothDevice device = getDevice(address);
debugLog("deviceFoundCallback: Remote Address is:" + device);
DeviceProperties deviceProp = getDeviceProperties(device);
if (deviceProp == null) {
errorLog("Device Properties is null for Device:" + device);
return;
}
Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE,device)
intent.putExtra(BluetoothDevice.EXTRA_CLASS, new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));
intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
}
到这里就是给界面发广播,应用层收到广播显示出来,通过这个handle,这个handle可以在BluetoothEventManager.java +90 +144的构造函数里找到
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Handler handler = mHandlerMap.get(action);
if (handler != null) {
handler.onReceive(context, intent, device);
}
}
};
“这里handle对应要看DeviceFoundHandler, +207 也就是下面贴出来的代码,
private class DeviceFoundHandler implements Handler {
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
........................
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
// callback to UI to create Preference for new device
dispatchDeviceAdded(cachedDevice);
}
......................
}
}
.........
234 private void dispatchDeviceAdded(CachedBluetoothDevice
cachedDevice) {
235 synchronized (mCallbacks) {
236 for (BluetoothCallback callback : mCallbacks)
{
callback.onDeviceAdded(cachedDevice);
238 }
239 }
240 }
在if语句中dispatchDeviceAdded()向界面分发消息,最后处理消息的地方在这里,搜索onDeviceAdded,已经到settings应用里了
/packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +160
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
if (mDevicePreferenceMap.get(cachedDevice) != null) {
return;
}
// Prevent updates while the list shows one of the state messages
if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;
if (mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
第二条路线
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java +621
611 void discoveryStateChangeCallback(int state) {
612 infoLog("Callback:discoveryStateChangeCallback with state:" + state);
613 synchronized (mObject) {
614 Intent intent;
615 if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) {
616 mDiscovering = false;
617 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
618 mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
619 } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) {
620 mDiscovering = true;
621 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
622 mService.sendBroadcast(intent, mService.BLUETOOTH_PERM);
623 }
624 }
625 }
sendBroadcast发送intent,action为BluetoothAdapter.ACTION_DISCOVERY_STARTED
packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEventManager.java +88
59 void addHandler(String action, Handler handler) {
60 mHandlerMap.put(action, handler);
61 mAdapterIntentFilter.addAction(action);
62 }
74 BluetoothEventManager(LocalBluetoothAdapter adapter,
75 CachedBluetoothDeviceManager deviceManager, Context context) {
76 mLocalAdapter = adapter;
77 mDeviceManager = deviceManager;
78 mAdapterIntentFilter = new IntentFilter();
79 mProfileIntentFilter = new IntentFilter();
80 mHandlerMap = new HashMap<String, Handler>();
81 mContext = context;
82
83 // Bluetooth on/off broadcasts
84 addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
85
86 // Discovery broadcasts
87 Log.e(TAG, "broadcasts6666666666666666666666666");
88 addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
89 addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
90 addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
91 addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
92 addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
93
94 Log.e(TAG, "broadcasts6666666666666666666666666");
95 // Pairing broadcasts
96 addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
97 addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
98
99 // Fine-grained state broadcasts
100 addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
101 addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
102
103 // Dock event broadcasts
104 addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
105
106 mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
107 }
108
109 void registerProfileIntentReceiver() {
110 mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter);
111 }
指定广播mProfileIntentFilter(action),和mBroadcastReceiver。
144 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
145 @Override
146 public void onReceive(Context context, Intent intent) {
147 Log.e(TAG, "shinan.com2-start-1");
148 String action = intent.getAction();
149 BluetoothDevice device = intent
150 .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
151
152 Handler handler = mHandlerMap.get(action);
153 if (handler != null) {
154 Log.e(TAG, action);
155
156 Log.e(TAG, "-----------------" + context);
157 Log.e(TAG, "-----------------" + intent);
158 Log.e(TAG, "-----------------" + device);
159 Log.e(TAG, "shinan.com2-start-2");
160 // if(device != null)
161 handler.onReceive(context, intent, device);
162
163 Log.e(TAG, "shinan.com2-start-3");
164 }
165 }
166 };
最后执行handler.onReceive(context, intent, device);
实现onReceive的方法有多个,
168 private class AdapterStateChangedHandler implements Handler {
169 public void onReceive(Context context, Intent intent,
170 BluetoothDevice device) {
171 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
172 BluetoothAdapter.ERROR);
173 // update local profiles and get paired devices
174 mLocalAdapter.setBluetoothStateInt(state);
175 // send callback to update UI and possibly start scanning
176 synchronized (mCallbacks) {
177 for (BluetoothCallback callback : mCallbacks) {
178 callback.onBluetoothStateChanged(state);
179 }
180 }
181 // Inform CachedDeviceManager that the adapter state has changed
182 mDeviceManager.onBluetoothStateChanged(state);
183 }
184 }
186 private class ScanningStateChangedHandler implements Handler {
187 private final boolean mStarted;
188
189 ScanningStateChangedHandler(boolean started) {
190 mStarted = started;
191 }
192 public void onReceive(Context context, Intent intent,
193 BluetoothDevice device) {
194 synchronized (mCallbacks) {
195 for (BluetoothCallback callback : mCallbacks) {
196 callback.onScanningStateChanged(mStarted);
197 Log.e(TAG, "*******************************************" + callback);
198 }
199 }
200 Log.e(TAG, "++++++++++++++++++++++++++++++++++++++++++++++" + mStarted );
201 mDeviceManager.onScanningStateChanged(mStarted);
202 LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
203 Log.e(TAG, "++++++++++++++++++++++++++++++++++++++++++++++" + context );
204 }
205 }
.onScanningStateChanged(mStarted)的方法实现有两种分别如下:
第一种 201行的mDeviceManager.onScanningStateChanged(mStarted);方法定义之处在packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java +124
124 public synchronized void onScanningStateChanged(boolean started) {
125 if (!started) return;
126
127 // If starting a new scan, clear old visibility
128 // Iterate in reverse order since devices may be removed.
129 for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
130 CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
131 cachedDevice.setVisible(false);
132
133 Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%====3");
134 }
135 }
第二种 196行的callback.onScanningStateChanged(mStarted); 的方法定义之处在packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSettings.java +391
391 public void onScanningStateChanged(boolean started) {
392 super.onScanningStateChanged(started);
393 // Update options' enabled state
394 Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bluetoothsetting");
395 if (getActivity() != null) {
396
397 Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bluetoothsetting");
398 getActivity().invalidateOptionsMenu();
399
400 Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bluetoothsetting");
401 }
402 }
上面其中的392行super.onScanningStateChanged(started)
定义之处在packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +208
208 public void onScanningStateChanged(boolean started) {
209
210 Log.e(TAG, "#############################snmu######" + snmu_3);
211 Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%====4");
212 updateProgressUi(started);
213 Log.e(TAG, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=====4");
214 }
开关打开后的操作:
BluetoothSettings.java +282 +260
LocalBluetoothAdapter.java +141
frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java +840
核心问题所在路径
packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +207
packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothEventManager.java +88,89
packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java +156
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java +273
packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothSettings.java +287 +391 +328
本次任务耗时半月完成,第一次接触安卓,进度比较慢,思路不是那么清晰,
Android中bluetooth的架构
Settings App:用于构造设置中的UI。就是我们在手机打开设置时所看到的打开/关闭蓝牙的UI操作。
Bluetooth App:这一块在图中没有画出来,他并不直接体现在UI上,可以理解为一个后台运行的apk。包括了蓝牙文件发送(OPP)和电话薄传输(PBAP)两个部分。
在中间Framework层,主要实现了各种API,这些API最终都是要通过jni层调入到下面来具体实现的。当然,他们还承担着接受底层消息的重任,这些消息也是要最终反馈到UI层的。
kernel层之下就是我们的bluetooth的芯片接口driver,
kernel\drivers\bluetoothBluetooth
external\bluetooth\bluedroid BlueZ (应用空间协议),官方蓝牙协议栈。
首先很容易就会发现一个和UI上很相关的代码位于packages/apps/Settings/src/com/android/settings/目录下。基本而言,各种UI上的处理都是在这个目录的bluetooth文件夹下实现的。所以,一般对蓝牙的打开/关闭,搜索,配对等等的按钮的处理,都是从这里开始的,这里也将是我们阅读代码的第一步。
我们都了解Android的系统架构,app层一般都调用到framework去进行进一步的实现,蓝牙也不例外。在framework层,蓝牙的代码主要位于frameworks/base/core/java/android/bluetooth目录下面。这个文件基本属于API的类型,向上层UI提供了所需要的API,换句话说,上层的UI比如Settings那边的代码都是通过这个文件夹下的文件进行调用的。然而,这个文件夹也只是client端的代码而已,它的servier端的代码大部分位于
frameworks/base/core/java/android/server目录下面,这里就是直接建立于jni层之上的代码了,负责向jni的调用,同时也负责从jni层接收相应的消息,从而反馈到UI层。
Framework层之下就是jni层了,这个比较简单,都位于frameworks/base/core/jni这个目录下面。Android4.0的代码还是基于bluez的,所以,这里也就是通过dbus和bluez进行通信了。说到bluez,它的代码基本位于external/bluetooth/bluez目录下。应该说是一个比较好的蓝牙stack了。他在tools目录下还提供了一些tool,其中hciattach和hcidump两个tool是非常有用的,前者在bluetooth的初始化中占有极为重要的地位,后者则在日常的debug过程中不可或缺。
Jni层之下就是kernel层了,相对而言,kernel层的代码还是蛮好找的,一份为stack,位于kernel/net/bluetooth目录下面,HCI,L2CAP,RFCOMM等的代码实现基本都是在这里面了。另一份则位于kernel/driver/bluetooth目录下面,各家蓝牙方案的driver都位于这里。
.常用类和名词解释:
\packages\apps\Settings\src\com\android\settings\bluetooth 目录下
BluetoothEnabler.java 界面上蓝牙开启、关闭的开关就是它了,
BluetoothSettings.java 主界面,用于管理配对和连接设备
LocalBluetoothManager.java 提供了蓝牙API上的简单调用接口,这里只是开始。
CachedBluetoothDevice.java 描述蓝牙设备的类,对BluetoothDevice的再封装
BluetoothPairingDialog.java 那个配对提示的对话框
这个界面的实现是在这个文件中:/packages/apps/Settings/res/xml/
bluetoothEventManager是用来管理api那边传过来的broadcast和callback,他会根据各个broadcast进行最终的分配,
BluetoothEventManager(LocalBluetoothAdapter adapter,
CachedBluetoothDeviceManager deviceManager, Context context) {
mLocalAdapter = adapter;
mDeviceManager = deviceManager;
mAdapterIntentFilter = new IntentFilter();
mProfileIntentFilter = new IntentFilter();
mHandlerMap = new HashMap<String, Handler>();
mContext = context;
// Bluetooth on/off broadcasts
// ACTION_STATE_CHANGED,在蓝牙的on和off的时候会发出
addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
//这两个是扫描的broadcast,分别表示开始扫描和停止扫描
// Discovery broadcasts
addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
//这是扫描到设备和设备消失的broadcast
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
//这个是设备名字改变的action
addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
// Pairing broadcasts
//这个是设备配对状态改变的action,比如正在配对,已经配对之类的
addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
//取消配对的handler
addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
// Fine-grained state broadcasts
//CLASS和UUID改变的action
addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
// Dock event broadcasts
//dock的event
addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
//注册对这些action处理的receiver
mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
}
BluetoothEventManager—用于管理从framework的bluetooth api那边上来的broadcast和callback,并把这些反馈到对应的class中去。
在打开Settings的时候,我们看到的ui上蓝牙相关的内容已经全部讲解完毕了。回顾一下,总得来说,就是首先有一个header的列表,然后在onBuildHeaders中会把这个列表加载进来,然后根据每个header不同的类型决定是否加入一些别的元素,比如按钮之类的。然后具体关联到bluetooth中去,根据bluetooth当时处于的状态显示对应的按钮状况,如实是否处于打开之类的。大概的流程就是这样了
路径 packages/apps/Settings/AndroidManifest.xml +326
先来看一下xml中fragment的设置:
android:fragment="com.android.settings.bluetooth.BluetoothSettings"
所以,很明确,我们要去看BluetoothSettings了。
public final class BluetoothSettings extends DeviceListPreferenceFragment
可以很明确地看到BluetoothSettings是扩展DeviceListPreferenceFragment,而BluetoothSettings中并没有重写onCreate()方法,所以,我们去DeviceListPreferenceFragment看看。
2————————————————————–
logcat 捕捉的错误信息
--------- beginning of crash
528 F/libc ( 1400): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x10 in tid 1400 (ndroid.settings)
529 I/DEBUG ( 95): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
530 I/DEBUG ( 95): Build fingerprint: 'Ingenic/dorado/dorado:5.0/LRX21M/snmu02281416:userdebug/test-keys'
531 I/DEBUG ( 95): Revision: '0'
532 I/DEBUG ( 95): ABI: 'mips'
533 I/DEBUG ( 95): pid: 1400, tid: 1400, name: ndroid.settings >>> com.android.settings <<<
534 I/DEBUG ( 95): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10
535 I/DEBUG ( 95): zr 00000000 at 00000001 v0 00001988 v1 00000000
536 I/DEBUG ( 95): a0 2fcd6c30 a1 00000662 a2 00000000 a3 7f86dad0
537 I/DEBUG ( 95): t0 7f800001 t1 00000000 t2 73f69300 t3 00000001
538 I/DEBUG ( 95): t4 54442d18 t5 3ff921fb t6 54442d18 t7 400921fb
539 I/DEBUG ( 95): s0 73f07800 s1 73efea4c s2 7f86fe8c s3 00000004
540 I/DEBUG ( 95): s4 2f7ebb10 s5 7f86fe10 s6 7f86fe00 s7 0000b7a4
541 I/DEBUG ( 95): t8 00000014 t9 73e041e8 k0 00000000 k1 00000000
542 I/DEBUG ( 95): gp 73f018c0 sp 7f86da58 s8 7f86fd70 ra 73a76b84
543 I/DEBUG ( 95): hi 00000000 lo 00000900 bva 00000010 epc 73e04244
544 I/DEBUG ( 95):
545 I/DEBUG ( 95): backtrace:
546 I/DEBUG ( 95): #00 pc 00455244 /system/lib/libart.so (artAllocObjectFromCodeRosAlloc+92)
547 I/DEBUG ( 95): #01 pc 000c7b84 /system/lib/libart.so (art_quick_alloc_object_rosalloc+68)
548 I/DEBUG ( 95): #02 pc 0173884c /data/dalvik-cache/mips/system@framework@boot.oat
549 I/DEBUG ( 95):
550 I/DEBUG ( 95): Tombstone written to: /data/tombstones/tombstone_03
mips-linux-gnu-addr2line -f -e ./out/target/product/dorado/system/lib/libart.so 0x000c7b84 (输出日志中最上面的pc值,可以回溯最终函数调用顺序)
cd art grep -rn“artAllocObjectFromCode”.
./runtime/entrypoints/quick/quick_alloc_entrypoints.cc:29:extern "C" mirror::Object* artAllocObjectFromCode ##suffix##suffix2
vim quick_alloc_entrypoints.cc +29
确定是这个函数 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)