平台

RK3288 + Android 7.1

概述

本文用于跟踪android获取蓝牙MAC接口实现的代码流程.

APP FRAMEWORK Bluetooth JNI HAL getAddress() bindService getAddress() initNative adapter_properties_callback APP FRAMEWORK Bluetooth JNI HAL

实现与参考代码

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

            <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. 随机生成

更多相关文章

  1. Android 蓝牙4.0踩坑—扫描不到设备
  2. Android中蓝牙通信的实现
  3. [置顶] Android 使用Hprose 调用Https接口
  4. android属性android:largeHeap
  5. android中进入设置页面(常见网络设置页面,设置页面,蓝牙页面等等)的a
  6. [置顶] Android ble低功耗蓝牙开发

随机推荐

  1. Android中SQLite操作示例
  2. Mac 10.12 快速下载 Android 源码
  3. Android关于SD卡的读写操作及固定图片大
  4. Android(安卓)DLNA
  5. 解决 Android模拟器无法上网问题——Host
  6. android UDID获取:android 设备SN的获取
  7. android中自定义播放器的实现
  8. 访问本地服务器
  9. Android 中的布局方式之线性布局
  10. 极光推送使用实例(三) Android客户端