【android bluetooth 框架分析 04】【bt-framework 层详解 2】【如何配置和启动蓝牙profile服务】

发布于:2025-06-12 ⋅ 阅读:(26) ⋅ 点赞:(0)

1. 问题

蓝牙协议栈在启动的时候,会启动很多协议服务, 例如 A2dpService、A2dpSinkService、AvrcpTargetService、AvrcpControllerService、BassClientService、BatteryService、CsipSetCoordinatorService、HeadsetService、HeadsetClientService …

你是否都清楚, 这些服务都是在哪里配置启动的?

如果不太清楚的话,今天我们就来梳理一下。

2. 如何在协议栈中配置支持的profile

当我们蓝牙服务进程被拉起时,会首先调用到

  • android/app/src/com/android/bluetooth/btservice/AdapterApp.java
package com.android.bluetooth.btservice;

import android.app.Application;
import android.util.Log;

public class AdapterApp extends Application {
    private static final String TAG = "BluetoothAdapterApp";
    private static final boolean DBG = AdapterService.DBG; //false;
    //For Debugging only
    private static int sRefCount = 0;

    static {
        if (DBG) {
            Log.d(TAG, "Loading JNI Library");
        }
        System.loadLibrary("bluetooth_jni"); // 1. 首先会加载我们 native 的库
    }

    public AdapterApp() {
        // 2. 创建 AdapterApp 对象
        super();
        if (DBG) {
            synchronized (AdapterApp.class) {
                sRefCount++;
                Log.d(TAG, "REFCOUNT: Constructed " + this + " Instance Count = " + sRefCount);
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (DBG) {
            Log.d(TAG, "onCreate");
        }
        try {
            DataMigration.run(this);
        } catch (Exception e) {
            Log.e(TAG, "Migration failure: ", e);
        }
        // 3.调用 对应的配置初始化
        AdapterUtil.init(this);
        Config.init(this);
    }

    @Override
    protected void finalize() {
        if (DBG) {
            synchronized (AdapterApp.class) {
                sRefCount--;
                Log.d(TAG, "REFCOUNT: Finalized: " + this + ", Instance Count = " + sRefCount);
            }
        }
    }
}

        AdapterUtil.init(this);
        Config.init(this);

1. AdapterUtil.init

// android/app/src/com/android/bluetooth/btservice/AdapterUtil.java

    public static void init(@NonNull Context context) {
        sContext = context;
        sDualBluetooth = SystemProperties.getBoolean("persist.vendor.bluetooth.dual_bt", false);

		// 根据当前 进程的名字,来区分 是bt0 还是 bt1 的服务进程
        sAdapterIndex = Application.getProcessName().equals(sContext.getPackageName()) ?
               ADAPTER_DEFAULT : ADAPTER_1;
        // 获取对应的 adapter
        sAdapter = getAdapter(sAdapterIndex);
        // 是否支持双蓝牙方案
        sDualAdapterMode = SystemProperties.getBoolean("persist.bluetooth.dual_adapter_mode", false);
        sFilterDevice = getFilterDeviceConfig();

		// 如果是双蓝牙方案, bt0 需要监测 bt1 服务的状态。
        if (isDualAdapterMode() && isAdapterDefault()) {
            // In dual adapter mode, default adapter needs to monitor
            // new adapter's state.
            AdapterExt.create(sContext);
        }
        
		// 获取系统属性,check 判断当前 bt0 是否为 a2dpsink 角色。如果没有设置,默认 bt0 为 a2dpsink 角色
        sIsA2dpSinkRole = SystemProperties.getBoolean("persist.bluetooth.adapter0.isA2dpSink", true);

        // Init profile supported in Bluetooth adapter
        sProfiles = new HashMap<Integer, ArrayList<Integer>>(ADAPTER_NUMBER);

		// 无论 bt0 是作为 a2dpsink 还是 a2dpsource , 将都支持 GATT, GATT_SERVER profile.
        ArrayList<Integer> profileArray = new ArrayList<Integer>(Arrays.asList(
                BluetoothProfile.GATT,
                BluetoothProfile.GATT_SERVER));
        if (sIsA2dpSinkRole) {
            // 如果是 a2dpsink 角色,默认支持这么多 profile
            profileArray.add(BluetoothProfile.A2DP_SINK);
            profileArray.add(BluetoothProfile.AVRCP_CONTROLLER);
            profileArray.add(BluetoothProfile.HEADSET_CLIENT);
            profileArray.add(BluetoothProfile.PBAP_CLIENT);
            profileArray.add(BluetoothProfile.HID_HOST);
            profileArray.add(BluetoothProfile.MAP_CLIENT);
            profileArray.add(BluetoothProfile.PAN);
            profileArray.add(BluetoothProfile.HID_DEVICE);
            profileArray.add(BluetoothProfile.A2DP);
            profileArray.add(BluetoothProfile.AVRCP);
            profileArray.add(BluetoothProfile.OPP);
        } else {
            // 如果是 a2dp source : 默认支持如下
            profileArray.add(BluetoothProfile.A2DP);
            profileArray.add(BluetoothProfile.AVRCP);
            profileArray.add(BluetoothProfile.HID_HOST);
        }
        sProfiles.put(ADAPTER_DEFAULT, profileArray); // 将上述支持的协议数组,放置到 bt0 对应的 sProfiles 中

		// bt1 将默认支持如下协议
        sProfiles.put(ADAPTER_1, new ArrayList<Integer>(Arrays.asList(
                BluetoothProfile.A2DP,
                BluetoothProfile.AVRCP,
                BluetoothProfile.GATT,
                BluetoothProfile.GATT_SERVER,
                BluetoothProfile.HID_HOST,
                BluetoothProfile.BATTERY)));
    }



    public static boolean isProfileSupported(int profileId) {
        return sProfiles.get(sAdapterIndex).contains(profileId); // 获取 bt0 , bt1 支持的 profile
    }
  • AdapterUtil.init 主要是将 bt0/bt1 支持的协议,分别保存在 sProfiles 对应的数组中。
  • 在之后可以通过 AdapterUtil.isProfileSupported() 方法来获取 当前支持那些协议。

2. Config.init(this)

  • packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/Config.java
    static void init(Context ctx) {
		...
        ArrayList<Class> profiles = new ArrayList<>(PROFILE_SERVICES_AND_FLAGS.length);
        // 这里会遍历 PROFILE_SERVICES_AND_FLAGS 数组中的每一个 ProfileConfig 对象
        for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) {
            Log.i(TAG, "init: profile=" + config.mClass.getSimpleName() + ", enabled="
                    + config.mSupported);
            if (config.mSupported
                    && AdapterUtil.isProfileSupported(config.mProfileId)) {
                // 如果 PROFILE_SERVICES_AND_FLAGS 的配置和 ProfileConfig 的配置 都支持
                Log.i(TAG, "Add profile " + config.mClass.getSimpleName());
                // 会将该 profile 对应的 class 加入到 profiles 中
                profiles.add(config.mClass);
            }
        }
        // 最终将 支持的 profile 对应的 class 全部放入 sSupportedProfiles 中
        sSupportedProfiles = profiles.toArray(new Class[profiles.size()]);

		...
    }


    static Class[] getSupportedProfiles() {
        return sSupportedProfiles;
    }
  • Config.init: 将当前支持的 profile 对应的 class 全部放入 sSupportedProfiles 数组中
  • 可以通过 Config.getSupportedProfiles 获取到 支持的 profile 对应的 class.


    private static final ProfileConfig[] PROFILE_SERVICES_AND_FLAGS = {
            new ProfileConfig(AdapterUtil.getA2dpServiceClass(), A2dpService.isEnabled(),
                    BluetoothProfile.A2DP),
            new ProfileConfig(A2dpSinkService.class, A2dpSinkService.isEnabled(),
                    BluetoothProfile.A2DP_SINK),
            new ProfileConfig(AdapterUtil.getAvrcpTargetServiceClass(), AvrcpTargetService.isEnabled(),
                    BluetoothProfile.AVRCP),
            new ProfileConfig(AvrcpControllerService.class, AvrcpControllerService.isEnabled(),
                    BluetoothProfile.AVRCP_CONTROLLER),
            new ProfileConfig(BassClientService.class, BassClientService.isEnabled(),
                    BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT),
            new ProfileConfig(AdapterUtil.getBatteryServiceClass(), BatteryService.isEnabled(),
                    BluetoothProfile.BATTERY),
            new ProfileConfig(CsipSetCoordinatorService.class,
                    CsipSetCoordinatorService.isEnabled(),
                    BluetoothProfile.CSIP_SET_COORDINATOR),
            new ProfileConfig(HapClientService.class, HapClientService.isEnabled(),
                    BluetoothProfile.HAP_CLIENT),
            new ProfileConfig(HeadsetService.class, HeadsetService.isEnabled(),
                    BluetoothProfile.HEADSET),
            new ProfileConfig(HeadsetClientService.class, HeadsetClientService.isEnabled(),
                    BluetoothProfile.HEADSET_CLIENT),
            new ProfileConfig(HearingAidService.class, HearingAidService.isEnabled(),
                    BluetoothProfile.HEARING_AID),
            new ProfileConfig(HidDeviceService.class, HidDeviceService.isEnabled(),
                    BluetoothProfile.HID_DEVICE),
            new ProfileConfig(AdapterUtil.getHidHostServiceClass(), HidHostService.isEnabled(),
                    BluetoothProfile.HID_HOST),
            new ProfileConfig(AdapterUtil.getGattServiceClass(), GattService.isEnabled(),
                    BluetoothProfile.GATT),
            new ProfileConfig(LeAudioService.class, LeAudioService.isEnabled(),
                    BluetoothProfile.LE_AUDIO),
            new ProfileConfig(TbsService.class, TbsService.isEnabled(),
                    BluetoothProfile.LE_CALL_CONTROL),
            new ProfileConfig(BluetoothMapService.class, BluetoothMapService.isEnabled(),
                    BluetoothProfile.MAP),
            new ProfileConfig(MapClientService.class, MapClientService.isEnabled(),
                    BluetoothProfile.MAP_CLIENT),
            new ProfileConfig(McpService.class, McpService.isEnabled(),
                    BluetoothProfile.MCP_SERVER),
            new ProfileConfig(BluetoothOppService.class, BluetoothOppService.isEnabled(),
                    BluetoothProfile.OPP),
            new ProfileConfig(PanService.class, PanService.isEnabled(),
                    BluetoothProfile.PAN),
            new ProfileConfig(BluetoothPbapService.class, BluetoothPbapService.isEnabled(),
                    BluetoothProfile.PBAP),
            new ProfileConfig(PbapClientService.class, PbapClientService.isEnabled(),
                    BluetoothProfile.PBAP_CLIENT),
            new ProfileConfig(SapService.class, SapService.isEnabled(),
                    BluetoothProfile.SAP),
            new ProfileConfig(VolumeControlService.class, VolumeControlService.isEnabled(),
                    BluetoothProfile.VOLUME_CONTROL),
    };

这里我们只分析一个例子:

new ProfileConfig(AdapterUtil.getA2dpServiceClass(), A2dpService.isEnabled(),
                    BluetoothProfile.A2DP),
// android/app/src/com/android/bluetooth/btservice/AdapterUtil.java
    public static Class getA2dpServiceClass() {
        return isAdapter1() ? A2dpExtService.class : A2dpService.class;
    }

AdapterUtil.getA2dpServiceClass(): 如何是 bt0 就使用 A2dpService.class , 如果是bt1 就是 A2dpExtService.class

// android/app/src/com/android/bluetooth/a2dp/A2dpService.java
    public static boolean isEnabled() {
        return BluetoothProperties.isProfileA2dpSourceEnabled().orElse(false);
    }

BluetoothProfile

framework/java/android/bluetooth/BluetoothProfile.java


    /**
     * Headset and Handsfree profile
     */
    int HEADSET = 1;

    /**
     * A2DP profile.
     */
    int A2DP = 2;

    /**
     * Health Profile
     *
     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
     * {@link BluetoothAdapter#listenUsingL2capChannel()}, or
     * {@link BluetoothDevice#createL2capChannel(int)}
     */
    @Deprecated
    int HEALTH = 3;

    /**
     * HID Host
     *
     * @hide
     */
    @SystemApi
    int HID_HOST = 4;

    /**
     * PAN Profile
     *
     * @hide
     */
    @SystemApi
    int PAN = 5;

    /**
     * PBAP
     *
     * @hide
     */
    @SystemApi
    int PBAP = 6;

    /**
     * GATT
     */
    int GATT = 7;

    /**
     * GATT_SERVER
     */
    int GATT_SERVER = 8;

    /**
     * MAP Profile
     *
     * @hide
     */
    @SystemApi
    int MAP = 9;

    /*
     * SAP Profile
     * @hide
     */
    int SAP = 10;

    /**
     * A2DP Sink Profile
     *
     * @hide
     */
    @SystemApi
    int A2DP_SINK = 11;

    /**
     * AVRCP Controller Profile
     *
     * @hide
     */
    @SystemApi
    int AVRCP_CONTROLLER = 12;

    /**
     * AVRCP Target Profile
     *
     * @hide
     */
    int AVRCP = 13;

    /**
     * Headset Client - HFP HF Role
     *
     * @hide
     */
    @SystemApi
    int HEADSET_CLIENT = 16;

    /**
     * PBAP Client
     *
     * @hide
     */
    @SystemApi
    int PBAP_CLIENT = 17;

    /**
     * MAP Messaging Client Equipment (MCE)
     *
     * @hide
     */
    @SystemApi
    int MAP_CLIENT = 18;

    /**
     * HID Device
     */
    int HID_DEVICE = 19;

    /**
     * Object Push Profile (OPP)
     *
     * @hide
     */
    @SystemApi
    int OPP = 20;

    /**
     * Hearing Aid Device
     *
     */
    int HEARING_AID = 21;

    /**
     * LE Audio Device
     *
     */
    int LE_AUDIO = 22;

    /**
     * Volume Control profile
     *
     * @hide
     */
    @SystemApi
    int VOLUME_CONTROL = 23;

    /**
     * @hide
     * Media Control Profile server
     *
     */
    int MCP_SERVER = 24;

    /**
     * Coordinated Set Identification Profile set coordinator
     *
     */
    int CSIP_SET_COORDINATOR = 25;

    /**
     * LE Audio Broadcast Source
     *
     * @hide
     */
    @SystemApi
    int LE_AUDIO_BROADCAST = 26;

    /**
     * @hide
     * Telephone Bearer Service from Call Control Profile
     *
     */
    int LE_CALL_CONTROL = 27;

    /*
     * Hearing Access Profile Client
     *
     */
    int HAP_CLIENT = 28;

    /**
     * LE Audio Broadcast Assistant
     *
     * @hide
     */
    @SystemApi
    int LE_AUDIO_BROADCAST_ASSISTANT = 29;

    /**
     * Battery Service
     *
     * @hide
     */
    int BATTERY = 30;

    /**
     * Max profile ID. This value should be updated whenever a new profile is added to match
     * the largest value assigned to a profile.
     *
     * @hide
     */
    int MAX_PROFILE_ID = 30;
Profile ID 名称 功能说明 使用场景示例
1 HEADSET Headset Profile (HSP) & Hands-Free Profile (HFP)。支持音频通话传输、控制语音呼叫。 车载蓝牙通话、蓝牙耳机通话
2 A2DP 高质量音频单向传输(Advanced Audio Distribution Profile)。 手机播放音乐到蓝牙音箱/耳机
3 HEALTH (已废弃) 旧版医疗设备通信协议(HDP),基于 MCAP。 旧版健康设备,如血压计(不推荐)
4 HID_HOST 支持作为 HID Host 使用,如连接键盘/鼠标。 安卓设备接蓝牙键盘或鼠标
5 PAN Personal Area Networking,蓝牙网络共享协议。 手机共享网络给车机或平板
6 PBAP Phone Book Access Profile,提供联系人信息读取服务。 车机同步手机联系人
7 GATT Generic Attribute Profile,用于 BLE 客户端角色。 App 读取 BLE 设备的数据,如运动手环
8 GATT_SERVER BLE GATT 服务端。 手环或传感器暴露服务给手机
9 MAP Message Access Profile,支持消息通知和读取。 车机读取短信内容
10 SAP SIM Access Profile,让蓝牙设备访问手机 SIM 卡。 车机通过手机 SIM 打电话
11 A2DP_SINK 支持作为音频接收端(Sink)使用,接收 A2DP 音频流。 车机接收手机的音频
12 AVRCP_CONTROLLER 控制设备上的媒体播放(AVRCP Controller Role)。 蓝牙耳机控制手机音乐播放
13 AVRCP AVRCP Target Role,被控制设备的媒体控制接口。 手机被蓝牙耳机控制播放/暂停
16 HEADSET_CLIENT 以 HFP HF 角色发起电话连接。 手机作为控制端连接车机
17 PBAP_CLIENT PBAP 客户端,从服务器读取联系人。 手机从车机导入联系人(不常见)
18 MAP_CLIENT MAP 客户端,主动访问消息服务。 手机从车机读取短信
19 HID_DEVICE 将本机作为蓝牙 HID 设备,例如模拟键盘、鼠标。 手机变身成蓝牙遥控器/键盘
20 OPP Object Push Profile,用于文件传输(已较少使用)。 蓝牙发送联系人/图片
21 HEARING_AID 支持助听器通信(低延迟、高同步性)。 手机连接助听器设备
22 LE_AUDIO 支持 BLE Audio 传输(多路、广播、低功耗)。 多设备同步播放、语音辅助功能
23 VOLUME_CONTROL 控制远端设备音量(LE Audio)。 手机调整 BLE 音箱音量
24 MCP_SERVER Media Control Profile 服务端角色。 播放设备被远端控制(BLE)
25 CSIP_SET_COORDINATOR BLE 同步组协调器(Coordinated Set Identification)。 同步多只音箱播放 BLE 音频
26 LE_AUDIO_BROADCAST BLE 音频广播源。 手机向公众广播音频
27 LE_CALL_CONTROL BLE 电话控制服务(Call Control Profile)。 耳机控制手机拨打/挂断电话
28 HAP_CLIENT Hearing Access Profile 客户端。 手机访问助听器服务
29 LE_AUDIO_BROADCAST_ASSISTANT 辅助设备帮广播设备寻找接收者。 电视控制 BLE 音频广播目标
30 BATTERY BLE 电量服务,报告设备电池电量。 耳机电量显示在手机通知栏
  • @SystemApi:表示该接口/ID 是系统内部使用,普通应用无法直接访问。

  • @hide:Android SDK 不对外暴露该接口。

  • @Deprecated:表示该 Profile 已不再推荐使用,可能未来会被移除。

  • 多数 BLE 相关 Profile(如 GATT、LE_AUDIO)用于现代可穿戴/低功耗设备场景。

  • 传统 Profile(如 HSP、A2DP、PBAP)仍广泛用于车载娱乐、耳机等领域。

3. 小结

如何在协议栈中配置支持的profile?

  1. 首先我们需要在 AdapterUtil.init 中,添加每个蓝牙支持的 profile
  2. Config.init 中,需要根据 系统属性 将支持的 profile 对应的 class 加入到 sSupportedProfiles 中。其他类可以通过 Config.getSupportedProfiles()来获取 对应支持的 profile class.
        AdapterUtil.init(this);
        Config.init(this);

3. 子协议服务启动

前面我们已经知道了协议栈将我们要启动的 profile 对应的class 都已经加入到 sSupportedProfiles 中了。那对应的 profile 服务是在什么实际启动的呢?

  • android/app/src/com/android/bluetooth/btservice/AdapterState.java

    private class TurningOnState extends BaseAdapterState {

        @Override
        public void enter() {
            super.enter();
            sendMessageDelayed(BREDR_START_TIMEOUT, BREDR_START_TIMEOUT_DELAY);
            mAdapterService.startProfileServices(); // 开启启动 经典蓝牙的 各个 子 profile.
        }
  • 当 蓝牙服务进入 启动 经典蓝牙状态时: 会触发调用 startProfileServices

  • packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/AdapterService.java


    void startProfileServices() {
        debugLog("startCoreServices()");

        Class[] supportedProfileServices = Config.getSupportedProfiles(); // 获取 支持的 profiles 

        if ((supportedProfileServices.length == 1)
                && isGattService(supportedProfileServices[0].getSimpleName())) {
		...
        } else {
           // 挨个启动 profile 对应的服务
            setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON);
        }
    }


    public void setProfileServiceState(Class service, int state) {
		...
        Log.d(TAG, "setProfileServiceState: " + service + ", state: " + state);
        Intent intent = new Intent(this, service);
        intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
        startService(intent); // 通过 系统函数将  profile 对应的服务拉起来
    }
01-02 04:40:07.206918  2259  2658 I AdapterState0: OFF : entered 
01-02 04:40:07.348232  2259  2658 I AdapterState0: BLE_TURNING_ON : entered 
01-02 04:40:09.013738  2259  2658 I AdapterState0: BLE_ON : entered 

// 进入 TURNING_ON 开始启动各个子协议
01-02 04:40:09.042387  2259  2658 I AdapterState0: TURNING_ON : entered 


// 开始逐个启动 经典蓝牙的 各个子 profile
01-02 04:40:09.043423  2259  2658 D BluetoothAdapterService: setProfileServiceState: class com.android.bluetooth.a2dpsink.A2dpSinkService, state: 12
01-02 04:40:09.045134  2259  2658 D BluetoothAdapterService: setProfileServiceState: class com.android.bluetooth.avrcpcontroller.AvrcpControllerService, state: 12
01-02 04:40:09.046304  2259  2658 D BluetoothAdapterService: setProfileServiceState: class com.android.bluetooth.hfpclient.HeadsetClientService, state: 12



01-02 04:40:09.048206  2259  2259 D A2dpSinkService: onCreate



01-02 04:40:09.048721  2259  2658 D BluetoothAdapterService: setProfileServiceState: class com.android.bluetooth.hid.HidDeviceService, state: 12
01-02 04:40:09.053122  2259  2658 D BluetoothAdapterService: setProfileServiceState: class com.android.bluetooth.hid.HidHostService, state: 12
01-02 04:40:09.054909  2259  2658 D BluetoothAdapterService: setProfileServiceState: class com.android.bluetooth.pbapclient.PbapClientService, state: 12



01-02 04:40:09.075082  2259  2259 D AvrcpControllerService: onCreate
01-02 04:40:09.107154  2259  2259 D HeadsetClientService: onCreate
01-02 04:40:09.181937  2259  2259 D HidDeviceService: onCreate
01-02 04:40:09.187428  2259  2259 D HidHostService: onCreate
01-02 04:40:09.210880  2259  2259 D PbapClientService: onCreate
01-02 04:40:09.215510  2259  2259 D BluetoothMediaBrowserService: onCreate
01-02 04:40:09.228497  2259  2259 D HfpClientConnService: onCreate


01-02 04:40:09.238341  2259  2658 I AdapterState0: ON : entered 

4. 总结

本节从两个角度 阐述了 蓝牙服务中 配置 和 启动 经典蓝牙 profile 服务的流程。