RK3288 android7.1 蓝牙MAC地址获取

简介: RK3288 android7.1 蓝牙MAC地址获取

平台


RK3288 + Android 7.1


概述


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

image.png


实现与参考代码


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


相关文章
|
6月前
|
JavaScript Java Android开发
uniapp通过蓝牙传输数据 (安卓)
uniapp通过蓝牙传输数据 (安卓)
311 1
|
6月前
|
XML 物联网 API
Android Ble蓝牙App(五)数据操作
Android Ble蓝牙App(五)数据操作
651 0
|
6月前
|
编解码 Android开发
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)1
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)
356 1
|
6月前
|
编解码 开发工具 Android开发
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)2
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)2
413 2
|
3月前
|
Android开发
Android 配置蓝牙遥控器键值
本文详细介绍了Android系统中配置蓝牙遥控器键值的步骤,包括查看设备号、配置键位映射文件(kl文件)、部署kl文件以及调试过程,确保蓝牙遥控器的按键能正确映射到Android系统对应的按键功能。
150 1
|
6月前
|
Android开发
Android获取蓝牙设备列表的方法
Android获取蓝牙设备列表的方法
537 5
|
6月前
|
定位技术 Android开发
Android 12蓝牙报java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission
Android 12蓝牙报java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission
240 1
|
6月前
|
Android开发
Android监听蓝牙广播
Android监听蓝牙广播
63 1
|
6月前
|
Android开发
Android Mediatek NVRAM 加载 MAC 地址并禁用 MAC 地址更新
Android Mediatek NVRAM 加载 MAC 地址并禁用 MAC 地址更新
99 0
|
6月前
|
XML 物联网 API
Android Ble蓝牙App(二)连接与发现服务
Android Ble蓝牙App(二)连接与发现服务
210 1