平台
RK3288 + Android 7.1
概述
本文用于跟踪android获取蓝牙MAC接口实现的代码流程.
实现与参考代码
Android 提供了标准的接口用来访问蓝牙的MAC地址信息
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter(); String addr = bt.getAddress(); String name = bt.getName();//00:11:22:33:44:55
注意权限的申请
FRAMEWORK层
SDK接口的BluetoothAdapter源码如下:
|-- frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
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; } BluetoothAdapter(IBluetoothManager managerService) { if (managerService == null) { throw new IllegalArgumentException("bluetooth manager service is null"); } try { mServiceLock.writeLock().lock(); mService = managerService.registerAdapter(mManagerCallback); } catch (RemoteException e) { Log.e(TAG, "", e); } finally { mServiceLock.writeLock().unlock(); } mManagerService = managerService; mLeScanClients = new HashMap<LeScanCallback, ScanCallback>(); mToken = new Binder(); } public String getAddress() { try { return mManagerService.getAddress(); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; }
mManagerService服务接口, 由BluetoothService注册到系统服务中
|-- frameworks/base/services/core/java/com/android/server/BluetoothService.java
@Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService); } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mBluetoothManagerService.handleOnBootPhase(); } }
|-- frameworks/base/services/core/java/com/android/server/BluetoothManagerService.java
public String getAddress() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { Slog.w(TAG,"getAddress(): not allowed for non-active and non system user"); return null; } if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS) != PackageManager.PERMISSION_GRANTED) { return BluetoothAdapter.DEFAULT_MAC_ADDRESS; } try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) return mBluetooth.getAddress(); } catch (RemoteException e) { Slog.e(TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e); } finally { mBluetoothLock.readLock().unlock(); } // mAddress is accessed from outside. // It is alright without a lock. Here, bluetooth is off, no other thread is // changing mAddress return mAddress; } private class BluetoothServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName componentName, IBinder service) { String name = componentName.getClassName(); if (DBG) Slog.d(TAG, "BluetoothServiceConnection: " + name); Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); if (name.equals("com.android.bluetooth.btservice.AdapterService")) { msg.arg1 = SERVICE_IBLUETOOTH; } else if (name.equals("com.android.bluetooth.gatt.GattService")) { msg.arg1 = SERVICE_IBLUETOOTHGATT; } else { Slog.e(TAG, "Unknown service connected: " + name); return; } msg.obj = service; mHandler.sendMessage(msg); } public void onServiceDisconnected(ComponentName componentName) { // Called if we unexpectedly disconnect. String name = componentName.getClassName(); if (DBG) Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name); Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); if (name.equals("com.android.bluetooth.btservice.AdapterService")) { msg.arg1 = SERVICE_IBLUETOOTH; } else if (name.equals("com.android.bluetooth.gatt.GattService")) { msg.arg1 = SERVICE_IBLUETOOTHGATT; } else { Slog.e(TAG, "Unknown service disconnected: " + name); return; } mHandler.sendMessage(msg); } } private class BluetoothHandler extends Handler { boolean mGetNameAddressOnly = false; public BluetoothHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_GET_NAME_AND_ADDRESS: if (DBG) Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS"); try { mBluetoothLock.writeLock().lock(); if ((mBluetooth == null) && (!mBinding)) { if (DBG) Slog.d(TAG, "Binding to service to get name and address"); mGetNameAddressOnly = true; Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND); mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS); Intent i = new Intent(IBluetooth.class.getName()); if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT)) { mHandler.removeMessages(MESSAGE_TIMEOUT_BIND); } else { mBinding = true; } } else if (mBluetooth != null) { try { storeNameAndAddress(mBluetooth.getName(), mBluetooth.getAddress()); } catch (RemoteException re) { Slog.e(TAG, "Unable to grab names", re); } if (mGetNameAddressOnly && !mEnable) { unbindAndFinish(); } mGetNameAddressOnly = false; } } finally { mBluetoothLock.writeLock().unlock(); } break; //... case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); IBinder service = (IBinder) msg.obj; try { mBluetoothLock.writeLock().lock(); 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; mBluetoothBinder = service; mBluetooth = IBluetooth.Stub.asInterface(service); if (!isNameAndAddressSet()) { Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS); mHandler.sendMessage(getMsg); if (mGetNameAddressOnly) return; } try { boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver, Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1); if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) { Slog.e(TAG,"IBluetooth.configHciSnoopLog return false"); } } catch (RemoteException e) { Slog.e(TAG,"Unable to call configHciSnoopLog", e); } //Register callback object try { mBluetooth.registerCallback(mBluetoothCallback); } catch (RemoteException re) { Slog.e(TAG, "Unable to register BluetoothCallback",re); } //Inform BluetoothAdapter instances that service is up sendBluetoothServiceUpCallback(); //Do enable request try { if (mQuietEnable == false) { if (!mBluetooth.enable()) { Slog.e(TAG,"IBluetooth.enable() returned false"); } } else { if (!mBluetooth.enableNoAutoConnect()) { Slog.e(TAG,"IBluetooth.enableNoAutoConnect() returned false"); } } } catch (RemoteException e) { Slog.e(TAG,"Unable to call enable()",e); } } finally { mBluetoothLock.writeLock().unlock(); } if (!mEnable) { waitForOnOff(true, false); handleDisable(); waitForOnOff(false, false); } break; }
PACKAGES
与HAL层的通讯实现放在蓝牙的APP中, 由蓝牙APP提供BIND服务:
|-- packages/apps/Bluetooth/AndroidManifest.xml
<service android:process="@string/process" android:name = ".btservice.AdapterService"> <intent-filter> <action android:name="android.bluetooth.IBluetooth" /> </intent-filter> </service>
|-- packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
private static class AdapterServiceBinder extends IBluetooth.Stub { //... public String getAddress() { if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!Utils.checkCallerAllowManagedProfiles(mService))) { Log.w(TAG, "getAddress() - Not allowed for non-active user and non system user"); return null; } AdapterService service = getService(); if (service == null) return null; return service.getAddress(); } //... } String getAddress() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); String addrString = null; byte[] address = mAdapterProperties.getAddress(); return Utils.getAddressStringFromByte(address); }
|-- packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
/** * @return the mAddress */ byte[] getAddress() { return mAddress; } void adapterPropertyChangedCallback(int[] types, byte[][] values) { Intent intent; int type; byte[] val; for (int i = 0; i < types.length; i++) { val = values[i]; type = types[i]; infoLog("adapterPropertyChangedCallback with type:" + type + " len:" + val.length); synchronized (mObject) { switch (type) { case AbstractionLayer.BT_PROPERTY_BDNAME: mName = new String(val); intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, mName); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mService.sendBroadcastAsUser(intent, UserHandle.ALL, mService.BLUETOOTH_PERM); debugLog("Name is: " + mName); break; case AbstractionLayer.BT_PROPERTY_BDADDR: mAddress = val; debugLog("Address is:" + Utils.getAddressStringFromByte(mAddress)); break; }
JNI
|-- packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
static bt_callbacks_t sBluetoothCallbacks = { sizeof(sBluetoothCallbacks), adapter_state_change_callback, adapter_properties_callback, remote_device_properties_callback, device_found_callback, discovery_state_changed_callback, pin_request_callback, ssp_request_callback, bond_state_changed_callback, acl_state_changed_callback, callback_thread_event, dut_mode_recv_callback, le_test_mode_recv_callback, energy_info_recv_callback }; static bool initNative(JNIEnv* env, jobject obj) { ALOGV("%s:",__FUNCTION__); android_bluetooth_UidTraffic.clazz = (jclass) env->NewGlobalRef( env->FindClass("android/bluetooth/UidTraffic")); sJniAdapterServiceObj = env->NewGlobalRef(obj); sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField)); if (sBluetoothInterface) { int ret = sBluetoothInterface->init(&sBluetoothCallbacks); if (ret != BT_STATUS_SUCCESS) { ALOGE("Error while setting the callbacks: %d\n", ret); sBluetoothInterface = NULL; return JNI_FALSE; } ret = sBluetoothInterface->set_os_callouts(&sBluetoothOsCallouts); if (ret != BT_STATUS_SUCCESS) { ALOGE("Error while setting Bluetooth callouts: %d\n", ret); sBluetoothInterface->cleanup(); sBluetoothInterface = NULL; return JNI_FALSE; } if ( (sBluetoothSocketInterface = (btsock_interface_t *) sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) { ALOGE("Error getting socket interface"); } return JNI_TRUE; } return JNI_FALSE; } static void adapter_properties_callback(bt_status_t status, int num_properties, bt_property_t *properties) { jobjectArray props; jintArray types; jbyteArray val; jclass mclass; if (!checkCallbackThread()) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } ALOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties); if (status != BT_STATUS_SUCCESS) { ALOGE("%s: Status %d is incorrect", __FUNCTION__, status); return; } val = (jbyteArray) callbackEnv->NewByteArray(num_properties); if (val == NULL) { ALOGE("%s: Error allocating byteArray", __FUNCTION__); return; } mclass = callbackEnv->GetObjectClass(val); /* (BT) Initialize the jobjectArray and jintArray here itself and send the initialized array pointers alone to get_properties */ props = callbackEnv->NewObjectArray(num_properties, mclass, NULL); if (props == NULL) { ALOGE("%s: Error allocating object Array for properties", __FUNCTION__); return; } types = (jintArray)callbackEnv->NewIntArray(num_properties); if (types == NULL) { ALOGE("%s: Error allocating int Array for values", __FUNCTION__); return; } // Delete the reference to val and mclass callbackEnv->DeleteLocalRef(mclass); callbackEnv->DeleteLocalRef(val); if (get_properties(num_properties, properties, &types, &props) < 0) { if (props) callbackEnv->DeleteLocalRef(props); if (types) callbackEnv->DeleteLocalRef(types); return; } callbackEnv->CallVoidMethod(sJniCallbacksObj, method_adapterPropertyChangedCallback, types, props); checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); callbackEnv->DeleteLocalRef(props); callbackEnv->DeleteLocalRef(types); return; }
在系统中存在两个hardware 的lib库:
rk3288:/ # ll /system/lib/hw/bluetooth* -rw-r--r-- 1 root root 1272568 2019-11-25 15:47 /system/lib/hw/bluetooth.default.so -rw-r--r-- 1 root root 1334308 2020-05-07 15:45 /system/lib/hw/bluetooth_rtk.default.so
主板使用的是8723的模块, 所以对应使用的是:bluetooth_rtk.default.so
HAL
|-- hardware/realtek/rtkbt/code/bt/btif/src/bluetooth.c
static int init(bt_callbacks_t *callbacks) { LOG_INFO(LOG_TAG, "%s", __func__); if (interface_ready()) return BT_STATUS_DONE; #ifdef BLUEDROID_DEBUG allocation_tracker_init(); #endif bt_hal_cbacks = callbacks; stack_manager_get_interface()->init_stack(); btif_debug_init(); #ifdef BLUETOOTH_RTK_API uipc_inited = FALSE; #endif return BT_STATUS_SUCCESS; }
|-- hardware/realtek/rtkbt/code/bt/btif/src/btif_core.c
bt_status_t btif_init_bluetooth() { LOG_DEBUG(LOG_TAG, "%s", __func__); bte_main_boot_entry(); /* As part of the init, fetch the local BD ADDR */ memset(&btif_local_bd_addr, 0, sizeof(bt_bdaddr_t)); btif_fetch_local_bdaddr(&btif_local_bd_addr); bt_jni_workqueue_thread = thread_new(BT_JNI_WORKQUEUE_NAME); if (bt_jni_workqueue_thread == NULL) { LOG_ERROR(LOG_TAG, "%s Unable to create thread %s", __func__, BT_JNI_WORKQUEUE_NAME); goto error_exit; } // Associate this workqueue thread with jni. btif_transfer_context(btif_jni_associate, 0, NULL, 0, NULL); return BT_STATUS_SUCCESS; error_exit:; thread_free(bt_jni_workqueue_thread); bt_jni_workqueue_thread = NULL; return BT_STATUS_FAIL; } static void btif_fetch_local_bdaddr(bt_bdaddr_t *local_addr) { char val[PROPERTY_VALUE_MAX] = {0}; uint8_t valid_bda = FALSE; int val_size = 0; int vflash_fd; const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0}; if ((vflash_fd = open("/dev/vflash", O_RDONLY)) != -1) { char bd_addr[6] = {0}; BTIF_TRACE_ERROR("Get local bdaddr from vflash"); #define VFLASH_READ_BDA 0x01 if(ioctl(vflash_fd, VFLASH_READ_BDA, (unsigned long)bd_addr) >= 0 && memcmp(bd_addr, null_bdaddr, BD_ADDR_LEN) != 0) { local_addr->address[0] = bd_addr[5]; local_addr->address[1] = bd_addr[4]; local_addr->address[2] = bd_addr[3]; local_addr->address[3] = bd_addr[2]; local_addr->address[4] = bd_addr[1]; local_addr->address[5] = bd_addr[0]; //local_addr->address[0] = local_addr->address[0] << 1; valid_bda = TRUE; BTIF_TRACE_DEBUG("Got Factory BDA %02X:%02X:%02X:%02X:%02X:%02X", local_addr->address[0], local_addr->address[1], local_addr->address[2], local_addr->address[3], local_addr->address[4], local_addr->address[5]); } close(vflash_fd); } //... }
读取MAC的优先级如下:
1.读取/dev/vflash
2.读取/dev/vendor_storage
3.读取属性PROPERTY_BT_BDADDR_PATH(ro.bt.bdaddr_path)指向的文件,
手上的平台对应的是 /data/misc/bluetooth/bdaddr
4.读取属性PERSIST_BDADDR_PROPERTY 和 FACTORY_BT_ADDR_PROPERTY
定义见: hardware/realtek/rtkbt/code/bt/btif/include/btif_common.h
5.随机生成