【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍

  • libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop

BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File) ,用于声明和管理 Bluetooth 模块相关的系统属性(System Properties) 。这些属性以结构化的方式定义,并由 sysprop 编译工具自动生成访问接口,供 Framework、HAL 或其他模块使用。

c 复制代码
# Copyright (C) 2021 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

module: "android.sysprop.BluetoothProperties"
owner: Platform

prop {
    api_name: "snoop_default_mode"
    type: Enum
    scope: Public
    access: ReadWrite
    enum_values: "empty|disabled|filtered|full"
    prop_name: "persist.bluetooth.btsnoopdefaultmode"
}

prop {
    api_name: "snoop_log_mode"
    type: Enum
    scope: Public
    access: ReadWrite
    enum_values: "empty|disabled|filtered|full"
    prop_name: "persist.bluetooth.btsnooplogmode"
}

prop {
    api_name: "factory_reset"
    type: Boolean
    scope: Public
    access: ReadWrite
    prop_name: "persist.bluetooth.factoryreset"
}

######## Bluetooth configurations

# Whether GAP BLE Privacy (RPA) is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isGapLePrivacyEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.core.gap.le.privacy.enabled"
}

# The default name of the device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "getDefaultDeviceName"
    type: String
    scope: Public
    access: Readonly
    prop_name: "bluetooth.device.default_name"
}

# The default class of device of the device, represented as a list of exactly 3 unsigned integers.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "getClassOfDevice"
    type: UIntList
    scope: Public
    access: Readonly
    prop_name: "bluetooth.device.class_of_device"
}

# Bluetooth operating voltage in millivolts available for vendors overlay.
# Used to calculate Bluetooth power consumption for a specific hardware.
prop {
    api_name: "getHardwareOperatingVoltageMv"
    type: Integer
    scope: Public
    access: Readonly
    prop_name: "bluetooth.hardware.power.operating_voltage_mv"
}

# Bluetooth idle current in milliamps available for vendors overlay.
# Used to calculate Bluetooth power consumption for a specific hardware.
prop {
    api_name: "getHardwareIdleCurrentMa"
    type: Integer
    scope: Public
    access: Readonly
    prop_name: "bluetooth.hardware.power.idle_cur_ma"
}

# Bluetooth transmit current in milliamps available for vendors overlay.
# Used to calculate Bluetooth power consumption for a specific hardware.
prop {
    api_name: "getHardwareTxCurrentMa"
    type: Integer
    scope: Public
    access: Readonly
    prop_name: "bluetooth.hardware.power.tx_cur_ma"
}

# Bluetooth receive current in milliamps available for vendors overlay.
# Used to calculate Bluetooth power consumption for a specific hardware.
prop {
    api_name: "getHardwareRxCurrentMa"
    type: Integer
    scope: Public
    access: Readonly
    prop_name: "bluetooth.hardware.power.rx_cur_ma"
}

# Whether Bluetooth should keep its state after reboot.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isSupportPersistedStateEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.framework.support_persisted_state"
}

# Whether Bluetooth should keep its state after reboot.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isAdapterAddressValidationEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.framework.adapter_address_validation"
}

# Whether the Advanced Audio Distribution Profile (A2DP) Sink role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileA2dpSinkEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.a2dp.sink.enabled"
}

# Whether the Advanced Audio Distribution Profile (A2DP) Source role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileA2dpSourceEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.a2dp.source.enabled"
}

# Whether the Android defined Audio Support for Hearing Aids (ASHA) central role over is enabled on
# this device. Set by vendors overlay, read at Bluetooth initialization.
prop {
    api_name: "isProfileAshaCentralEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.asha.central.enabled"
}

# Whether the Audio/Video Remote Control Profile (AVRCP) Controller role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileAvrcpControllerEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.avrcp.controller.enabled"
}

# Whether the Audio/Video Remote Control Profile (AVRCP) Target role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileAvrcpTargetEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.avrcp.target.enabled"
}

# Whether the Basic Audio Profile (BAP) broadcast assist role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileBapBroadcastAssistEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.bap.broadcast.assist.enabled"
}

# Whether the Basic Audio Profile (BAP) broadcast source role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileBapBroadcastSourceEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.bap.broadcast.source.enabled"
}

# Whether the Basic Audio Profile (BAP) unicast client role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileBapUnicastClientEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.bap.unicast.client.enabled"
}

# Whether the Battery Service profile (BAS) client role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileBasClientEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.bas.client.enabled"
}

# Whether the Broadcast Audio Scan Service profile (BASS) client role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileBassClientEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.bass.client.enabled"
}

# Whether the Coordinated Set Indentification Profile (CSIP) set coordinator role is enabled on this
# device. Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileCsipSetCoordinatorEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.csip.set_coordinator.enabled"
}

# Whether the Generic Attribute Profile (GATT) is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileGattEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.gatt.enabled"
}

# Whether the Hearing Aid Profile (HAP) client role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileHapClientEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.hap.client.enabled"
}

# Whether the Hands-Free Profile (HFP) Audio Gateway role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileHfpAgEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.hfp.ag.enabled"
}

# Whether the Hands-Free Profile (HFP) Hands-free role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileHfpHfEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.hfp.hf.enabled"
}

# Whether the Human Interface Device Profile (HID) device role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileHidDeviceEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.hid.device.enabled"
}

# Whether the Human Interface Device Profile (HID) host role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileHidHostEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.hid.host.enabled"
}

# Whether the Message Access Profile (MAP) Client role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileMapClientEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.map.client.enabled"
}

# Whether the Message Access Profile (MAP) Server role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileMapServerEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.map.server.enabled"
}

# Whether the Media Control Profile (MCP) server role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileMcpServerEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.mcp.server.enabled"
}

# Whether the Object Push Profile (OPP) is enabled on this device. The implementation of OPP
# supports both client and server roles. Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileOppEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.opp.enabled"
}

# Whether the Personal Area Networking Profile (PAN) NAP role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfilePanNapEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.pan.nap.enabled"
}

# Whether the Personal Area Networking Profile (PAN) PANU role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfilePanPanuEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.pan.panu.enabled"
}

# Whether the Phonebook Access Profile (PBAP) client role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfilePbapClientEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.pbap.client.enabled"
}

# Whether the Phonebook Access Profile (PBAP) server role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfilePbapServerEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.pbap.server.enabled"
}

# Whether the SIM Access Profile (SAP) server is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileSapServerEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.sap.server.enabled"
}

# Whether the Call Control Profile (CCP) server role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileCcpServerEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.ccp.server.enabled"
}

# Whether the Volume Control Profile (VCP) controller role is enabled on this device.
# Set by vendors overlay, read at Bluetooth initialization
prop {
    api_name: "isProfileVcpControllerEnabled"
    type: Boolean
    scope: Public
    access: Readonly
    prop_name: "bluetooth.profile.vcp.controller.enabled"
}

1. 编译后的产物

1. java

BluetoothProperties.sysprop 文件在 aosp 中会自动编译生成对应的 *.jar 和 .h

  • ./out/soong/.intermediates/system/libsysprop/srcs/PlatformProperties_java_gen/gen/sysprop/system/libsysprop/srcs/android/sysprop/BluetoothProperties.srcjar
    • 当前的 jar 中会存在 BluetoothProperties.java 文件
java 复制代码
// Generated by the sysprop generator. DO NOT EDIT!

package android.sysprop;

import android.os.SystemProperties;
import android.util.Log;

import java.lang.StringBuilder;
import java.util.ArrayList;
import java.util.function.Function;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.stream.Collectors;

public final class BluetoothProperties {
    private BluetoothProperties () {}

    private static Boolean tryParseBoolean(String str) {
        switch (str.toLowerCase(Locale.US)) {
            case "1":
            case "true":
                return Boolean.TRUE;
            case "0":
            case "false":
                return Boolean.FALSE;
            default:
                return null;
        }
    }

    private static Integer tryParseInteger(String str) {
        try {
            return Integer.valueOf(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static Integer tryParseUInt(String str) {
        try {
            return Integer.parseUnsignedInt(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static Long tryParseLong(String str) {
        try {
            return Long.valueOf(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static Long tryParseULong(String str) {
        try {
            return Long.parseUnsignedLong(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static Double tryParseDouble(String str) {
        try {
            return Double.valueOf(str);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static String tryParseString(String str) {
        return "".equals(str) ? null : str;
    }

    private static <T extends Enum<T>> T tryParseEnum(Class<T> enumType, String str) {
        try {
            return Enum.valueOf(enumType, str.toUpperCase(Locale.US));
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    private static <T> List<T> tryParseList(Function<String, T> elementParser, String str) {
        if ("".equals(str)) return new ArrayList<>();

        List<T> ret = new ArrayList<>();

        int p = 0;
        for (;;) {
            StringBuilder sb = new StringBuilder();
            while (p < str.length() && str.charAt(p) != ',') {
                if (str.charAt(p) == '\\') ++p;
                if (p == str.length()) break;
                sb.append(str.charAt(p++));
            }
            ret.add(elementParser.apply(sb.toString()));
            if (p == str.length()) break;
            ++p;
        }

        return ret;
    }

    private static <T extends Enum<T>> List<T> tryParseEnumList(Class<T> enumType, String str) {
        if ("".equals(str)) return new ArrayList<>();

        List<T> ret = new ArrayList<>();

        for (String element : str.split(",")) {
            ret.add(tryParseEnum(enumType, element));
        }

        return ret;
    }

    private static String escape(String str) {
        return str.replaceAll("([\\\\,])", "\\\\$1");
    }

    private static <T> String formatList(List<T> list) {
        StringJoiner joiner = new StringJoiner(",");

        for (T element : list) {
            joiner.add(element == null ? "" : escape(element.toString()));
        }

        return joiner.toString();
    }

    private static String formatUIntList(List<Integer> list) {
        StringJoiner joiner = new StringJoiner(",");

        for (Integer element : list) {
            joiner.add(element == null ? "" : escape(Integer.toUnsignedString(element)));
        }

        return joiner.toString();
    }

    private static String formatULongList(List<Long> list) {
        StringJoiner joiner = new StringJoiner(",");

        for (Long element : list) {
            joiner.add(element == null ? "" : escape(Long.toUnsignedString(element)));
        }

        return joiner.toString();
    }

    private static <T extends Enum<T>> String formatEnumList(List<T> list, Function<T, String> elementFormatter) {
        StringJoiner joiner = new StringJoiner(",");

        for (T element : list) {
            joiner.add(element == null ? "" : elementFormatter.apply(element));
        }

        return joiner.toString();
    }

    public static enum snoop_default_mode_values {
        EMPTY("empty"),
        DISABLED("disabled"),
        FILTERED("filtered"),
        FULL("full");
        private final String propValue;
        private snoop_default_mode_values(String propValue) {
            this.propValue = propValue;
        }
        public String getPropValue() {
            return propValue;
        }
    }

    public static Optional<snoop_default_mode_values> snoop_default_mode() {
        String value = SystemProperties.get("persist.bluetooth.btsnoopdefaultmode");
        return Optional.ofNullable(tryParseEnum(snoop_default_mode_values.class, value));
    }

    public static void snoop_default_mode(snoop_default_mode_values value) {
        SystemProperties.set("persist.bluetooth.btsnoopdefaultmode", value == null ? "" : value.getPropValue());
    }

    public static enum snoop_log_mode_values {
        EMPTY("empty"),
        DISABLED("disabled"),
        FILTERED("filtered"),
        FULL("full");
        private final String propValue;
        private snoop_log_mode_values(String propValue) {
            this.propValue = propValue;
        }
        public String getPropValue() {
            return propValue;
        }
    }

    public static Optional<snoop_log_mode_values> snoop_log_mode() {
        String value = SystemProperties.get("persist.bluetooth.btsnooplogmode");
        return Optional.ofNullable(tryParseEnum(snoop_log_mode_values.class, value));
    }

    public static void snoop_log_mode(snoop_log_mode_values value) {
        SystemProperties.set("persist.bluetooth.btsnooplogmode", value == null ? "" : value.getPropValue());
    }

    public static Optional<Boolean> factory_reset() {
        String value = SystemProperties.get("persist.bluetooth.factoryreset");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static void factory_reset(Boolean value) {
        SystemProperties.set("persist.bluetooth.factoryreset", value == null ? "" : value.toString());
    }

    public static Optional<Boolean> isGapLePrivacyEnabled() {
        String value = SystemProperties.get("bluetooth.core.gap.le.privacy.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<String> getDefaultDeviceName() {
        String value = SystemProperties.get("bluetooth.device.default_name");
        return Optional.ofNullable(tryParseString(value));
    }

    public static List<Integer> getClassOfDevice() {
        String value = SystemProperties.get("bluetooth.device.class_of_device");
        return tryParseList(v -> tryParseUInt(v), value);
    }

    public static Optional<Integer> getHardwareOperatingVoltageMv() {
        String value = SystemProperties.get("bluetooth.hardware.power.operating_voltage_mv");
        return Optional.ofNullable(tryParseInteger(value));
    }

    public static Optional<Integer> getHardwareIdleCurrentMa() {
        String value = SystemProperties.get("bluetooth.hardware.power.idle_cur_ma");
        return Optional.ofNullable(tryParseInteger(value));
    }

    public static Optional<Integer> getHardwareTxCurrentMa() {
        String value = SystemProperties.get("bluetooth.hardware.power.tx_cur_ma");
        return Optional.ofNullable(tryParseInteger(value));
    }

    public static Optional<Integer> getHardwareRxCurrentMa() {
        String value = SystemProperties.get("bluetooth.hardware.power.rx_cur_ma");
        return Optional.ofNullable(tryParseInteger(value));
    }

    public static Optional<Boolean> isSupportPersistedStateEnabled() {
        String value = SystemProperties.get("bluetooth.framework.support_persisted_state");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isAdapterAddressValidationEnabled() {
        String value = SystemProperties.get("bluetooth.framework.adapter_address_validation");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileA2dpSinkEnabled() {
        String value = SystemProperties.get("bluetooth.profile.a2dp.sink.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileA2dpSourceEnabled() {
        String value = SystemProperties.get("bluetooth.profile.a2dp.source.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileAshaCentralEnabled() {
        String value = SystemProperties.get("bluetooth.profile.asha.central.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileAvrcpControllerEnabled() {
        String value = SystemProperties.get("bluetooth.profile.avrcp.controller.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileAvrcpTargetEnabled() {
        String value = SystemProperties.get("bluetooth.profile.avrcp.target.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileBapBroadcastAssistEnabled() {
        String value = SystemProperties.get("bluetooth.profile.bap.broadcast.assist.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileBapBroadcastSourceEnabled() {
        String value = SystemProperties.get("bluetooth.profile.bap.broadcast.source.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileBapUnicastClientEnabled() {
        String value = SystemProperties.get("bluetooth.profile.bap.unicast.client.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileBasClientEnabled() {
        String value = SystemProperties.get("bluetooth.profile.bas.client.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileBassClientEnabled() {
        String value = SystemProperties.get("bluetooth.profile.bass.client.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileCsipSetCoordinatorEnabled() {
        String value = SystemProperties.get("bluetooth.profile.csip.set_coordinator.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileGattEnabled() {
        String value = SystemProperties.get("bluetooth.profile.gatt.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileHapClientEnabled() {
        String value = SystemProperties.get("bluetooth.profile.hap.client.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileHfpAgEnabled() {
        String value = SystemProperties.get("bluetooth.profile.hfp.ag.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileHfpHfEnabled() {
        String value = SystemProperties.get("bluetooth.profile.hfp.hf.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileHidDeviceEnabled() {
        String value = SystemProperties.get("bluetooth.profile.hid.device.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileHidHostEnabled() {
        String value = SystemProperties.get("bluetooth.profile.hid.host.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileMapClientEnabled() {
        String value = SystemProperties.get("bluetooth.profile.map.client.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileMapServerEnabled() {
        String value = SystemProperties.get("bluetooth.profile.map.server.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileMcpServerEnabled() {
        String value = SystemProperties.get("bluetooth.profile.mcp.server.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileOppEnabled() {
        String value = SystemProperties.get("bluetooth.profile.opp.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfilePanNapEnabled() {
        String value = SystemProperties.get("bluetooth.profile.pan.nap.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfilePanPanuEnabled() {
        String value = SystemProperties.get("bluetooth.profile.pan.panu.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfilePbapClientEnabled() {
        String value = SystemProperties.get("bluetooth.profile.pbap.client.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfilePbapServerEnabled() {
        String value = SystemProperties.get("bluetooth.profile.pbap.server.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileSapServerEnabled() {
        String value = SystemProperties.get("bluetooth.profile.sap.server.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileCcpServerEnabled() {
        String value = SystemProperties.get("bluetooth.profile.ccp.server.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }

    public static Optional<Boolean> isProfileVcpControllerEnabled() {
        String value = SystemProperties.get("bluetooth.profile.vcp.controller.enabled");
        return Optional.ofNullable(tryParseBoolean(value));
    }
}

如何使用:
c 复制代码
// android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java

import android.sysprop.BluetoothProperties;

    public static boolean isEnabled() {
        return BluetoothProperties.isProfileAvrcpTargetEnabled().orElse(false);
    }

2. native 层

aosp 编译系统会帮我们自动生成:

  • ./out/soong/.intermediates/system/libsysprop/srcs/libPlatformProperties/android_arm64_armv8-a-branchprot_static_hwasan/gen/sysprop/android/sysprop/BluetoothProperties.sysprop.cpp
  • ./out/soong/.intermediates/system/libsysprop/srcs/libPlatformProperties/android_arm64_armv8-a-branchprot_static_hwasan/gen/sysprop/public/include/android/sysprop/BluetoothProperties.sysprop.h
c 复制代码
// Generated by the sysprop generator. DO NOT EDIT!

#include <android/sysprop/BluetoothProperties.sysprop.h>

#include <cctype>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <limits>
#include <utility>

#include <strings.h>
#ifdef __BIONIC__
#include <sys/system_properties.h>
[[maybe_unused]] static bool SetProp(const char* key, const char* value) {
    return __system_property_set(key, value) == 0;
}
#else
#include <android-base/properties.h>
[[maybe_unused]] static bool SetProp(const char* key, const char* value) {
    android::base::SetProperty(key, value);
    return true;
}
#endif

#include <android-base/parseint.h>
#include <log/log.h>

namespace {

using namespace android::sysprop::BluetoothProperties;

template <typename T> T DoParse(const char* str);

constexpr const std::pair<const char*, snoop_default_mode_values> snoop_default_mode_list[] = {
    {"empty", snoop_default_mode_values::EMPTY},
    {"disabled", snoop_default_mode_values::DISABLED},
    {"filtered", snoop_default_mode_values::FILTERED},
    {"full", snoop_default_mode_values::FULL},
};

template <>
std::optional<snoop_default_mode_values> DoParse(const char* str) {
    for (auto [name, val] : snoop_default_mode_list) {
        if (strcmp(str, name) == 0) {
            return val;
        }
    }
    return std::nullopt;
}

std::string FormatValue(std::optional<snoop_default_mode_values> value) {
    if (!value) return "";
    for (auto [name, val] : snoop_default_mode_list) {
        if (val == *value) {
            return name;
        }
    }
    LOG_ALWAYS_FATAL("Invalid value %d for property persist.bluetooth.btsnoopdefaultmode", static_cast<std::int32_t>(*value));
    __builtin_unreachable();
}

constexpr const std::pair<const char*, snoop_log_mode_values> snoop_log_mode_list[] = {
    {"empty", snoop_log_mode_values::EMPTY},
    {"disabled", snoop_log_mode_values::DISABLED},
    {"filtered", snoop_log_mode_values::FILTERED},
    {"full", snoop_log_mode_values::FULL},
};

template <>
std::optional<snoop_log_mode_values> DoParse(const char* str) {
    for (auto [name, val] : snoop_log_mode_list) {
        if (strcmp(str, name) == 0) {
            return val;
        }
    }
    return std::nullopt;
}

std::string FormatValue(std::optional<snoop_log_mode_values> value) {
    if (!value) return "";
    for (auto [name, val] : snoop_log_mode_list) {
        if (val == *value) {
            return name;
        }
    }
    LOG_ALWAYS_FATAL("Invalid value %d for property persist.bluetooth.btsnooplogmode", static_cast<std::int32_t>(*value));
    __builtin_unreachable();
}

template <typename T> constexpr bool is_vector = false;

template <typename T> constexpr bool is_vector<std::vector<T>> = true;

template <> [[maybe_unused]] std::optional<bool> DoParse(const char* str) {
    static constexpr const char* kYes[] = {"1", "true"};
    static constexpr const char* kNo[] = {"0", "false"};

    for (const char* yes : kYes) {
        if (strcasecmp(yes, str) == 0) return std::make_optional(true);
    }

    for (const char* no : kNo) {
        if (strcasecmp(no, str) == 0) return std::make_optional(false);
    }

    return std::nullopt;
}

template <> [[maybe_unused]] std::optional<std::int32_t> DoParse(const char* str) {
    std::int32_t ret;
    return android::base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
}

template <> [[maybe_unused]] std::optional<std::uint32_t> DoParse(const char* str) {
    std::uint32_t ret;
    return android::base::ParseUint(str, &ret) ? std::make_optional(ret) : std::nullopt;
}

template <> [[maybe_unused]] std::optional<std::int64_t> DoParse(const char* str) {
    std::int64_t ret;
    return android::base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
}

template <> [[maybe_unused]] std::optional<std::uint64_t> DoParse(const char* str) {
    std::uint64_t ret;
    return android::base::ParseUint(str, &ret) ? std::make_optional(ret) : std::nullopt;
}

template <> [[maybe_unused]] std::optional<double> DoParse(const char* str) {
    int old_errno = errno;
    errno = 0;
    char* end;
    double ret = std::strtod(str, &end);
    if (errno != 0) {
        return std::nullopt;
    }
    if (str == end || *end != '\0') {
        errno = EINVAL;
        return std::nullopt;
    }
    errno = old_errno;
    return std::make_optional(ret);
}

template <> [[maybe_unused]] std::optional<std::string> DoParse(const char* str) {
    return *str == '\0' ? std::nullopt : std::make_optional(str);
}

template <typename Vec> [[maybe_unused]] Vec DoParseList(const char* str) {
    Vec ret;
    if (*str == '\0') return ret;
    const char* p = str;
    for (;;) {
        const char* r = p;
        std::string value;
        while (*r != ',') {
            if (*r == '\\') ++r;
            if (*r == '\0') break;
            value += *r++;
        }
        ret.emplace_back(DoParse<typename Vec::value_type>(value.c_str()));
        if (*r == '\0') break;
        p = r + 1;
    }
    return ret;
}

template <typename T> inline T TryParse(const char* str) {
    if constexpr(is_vector<T>) {
        return DoParseList<T>(str);
    } else {
        return DoParse<T>(str);
    }
}

[[maybe_unused]] std::string FormatValue(const std::optional<std::int32_t>& value) {
    return value ? std::to_string(*value) : "";
}

[[maybe_unused]] std::string FormatValue(const std::optional<std::uint32_t>& value) {
    return value ? std::to_string(*value) : "";
}

[[maybe_unused]] std::string FormatValue(const std::optional<std::int64_t>& value) {
    return value ? std::to_string(*value) : "";
}

[[maybe_unused]] std::string FormatValue(const std::optional<std::uint64_t>& value) {
    return value ? std::to_string(*value) : "";
}

[[maybe_unused]] std::string FormatValue(const std::optional<double>& value) {
    if (!value) return "";
    char buf[1024];
    std::sprintf(buf, "%.*g", std::numeric_limits<double>::max_digits10, *value);
    return buf;
}

[[maybe_unused]] std::string FormatValue(const std::optional<bool>& value) {
    return value ? (*value ? "true" : "false") : "";
}

template <typename T>
[[maybe_unused]] std::string FormatValue(const std::vector<T>& value) {
    if (value.empty()) return "";

    std::string ret;
    bool first = true;

    for (auto&& element : value) {
        if (!first) ret += ',';
        else first = false;
        if constexpr(std::is_same_v<T, std::optional<std::string>>) {
            if (element) {
                for (char c : *element) {
                    if (c == '\\' || c == ',') ret += '\\';
                    ret += c;
                }
            }
        } else {
            ret += FormatValue(element);
        }
    }

    return ret;
}

template <typename T>
T GetProp(const char* key, const char* legacy = nullptr) {
    std::string value;
#ifdef __BIONIC__
    auto pi = __system_property_find(key);
    if (pi != nullptr) {
        __system_property_read_callback(pi, [](void* cookie, const char*, const char* value, std::uint32_t) {
            *static_cast<std::string*>(cookie) = value;
        }, &value);
    }
#else
    value = android::base::GetProperty(key, "");
#endif
    if (value.empty() && legacy) {
        ALOGV("prop %s doesn't exist; fallback to legacy prop %s", key, legacy);
        return GetProp<T>(legacy);
    }
    return TryParse<T>(value.c_str());
}

}  // namespace

namespace android::sysprop::BluetoothProperties {

std::optional<snoop_default_mode_values> snoop_default_mode() {
    return GetProp<std::optional<snoop_default_mode_values>>("persist.bluetooth.btsnoopdefaultmode");
}

bool snoop_default_mode(const std::optional<snoop_default_mode_values>& value) {
    return SetProp("persist.bluetooth.btsnoopdefaultmode", FormatValue(value).c_str());
}

std::optional<snoop_log_mode_values> snoop_log_mode() {
    return GetProp<std::optional<snoop_log_mode_values>>("persist.bluetooth.btsnooplogmode");
}

bool snoop_log_mode(const std::optional<snoop_log_mode_values>& value) {
    return SetProp("persist.bluetooth.btsnooplogmode", FormatValue(value).c_str());
}

std::optional<bool> factory_reset() {
    return GetProp<std::optional<bool>>("persist.bluetooth.factoryreset");
}

bool factory_reset(const std::optional<bool>& value) {
    return SetProp("persist.bluetooth.factoryreset", FormatValue(value).c_str());
}

std::optional<bool> isGapLePrivacyEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.core.gap.le.privacy.enabled");
}

std::optional<std::string> getDefaultDeviceName() {
    return GetProp<std::optional<std::string>>("bluetooth.device.default_name");
}

std::vector<std::optional<std::uint32_t>> getClassOfDevice() {
    return GetProp<std::vector<std::optional<std::uint32_t>>>("bluetooth.device.class_of_device");
}

std::optional<std::int32_t> getHardwareOperatingVoltageMv() {
    return GetProp<std::optional<std::int32_t>>("bluetooth.hardware.power.operating_voltage_mv");
}

std::optional<std::int32_t> getHardwareIdleCurrentMa() {
    return GetProp<std::optional<std::int32_t>>("bluetooth.hardware.power.idle_cur_ma");
}

std::optional<std::int32_t> getHardwareTxCurrentMa() {
    return GetProp<std::optional<std::int32_t>>("bluetooth.hardware.power.tx_cur_ma");
}

std::optional<std::int32_t> getHardwareRxCurrentMa() {
    return GetProp<std::optional<std::int32_t>>("bluetooth.hardware.power.rx_cur_ma");
}

std::optional<bool> isSupportPersistedStateEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.framework.support_persisted_state");
}

std::optional<bool> isAdapterAddressValidationEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.framework.adapter_address_validation");
}

std::optional<bool> isProfileA2dpSinkEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.a2dp.sink.enabled");
}

std::optional<bool> isProfileA2dpSourceEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.a2dp.source.enabled");
}

std::optional<bool> isProfileAshaCentralEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.asha.central.enabled");
}

std::optional<bool> isProfileAvrcpControllerEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.avrcp.controller.enabled");
}

std::optional<bool> isProfileAvrcpTargetEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.avrcp.target.enabled");
}

std::optional<bool> isProfileBapBroadcastAssistEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.bap.broadcast.assist.enabled");
}

std::optional<bool> isProfileBapBroadcastSourceEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.bap.broadcast.source.enabled");
}

std::optional<bool> isProfileBapUnicastClientEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.bap.unicast.client.enabled");
}

std::optional<bool> isProfileBasClientEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.bas.client.enabled");
}

std::optional<bool> isProfileBassClientEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.bass.client.enabled");
}

std::optional<bool> isProfileCsipSetCoordinatorEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.csip.set_coordinator.enabled");
}

std::optional<bool> isProfileGattEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.gatt.enabled");
}

std::optional<bool> isProfileHapClientEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.hap.client.enabled");
}

std::optional<bool> isProfileHfpAgEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.hfp.ag.enabled");
}

std::optional<bool> isProfileHfpHfEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.hfp.hf.enabled");
}

std::optional<bool> isProfileHidDeviceEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.hid.device.enabled");
}

std::optional<bool> isProfileHidHostEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.hid.host.enabled");
}

std::optional<bool> isProfileMapClientEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.map.client.enabled");
}

std::optional<bool> isProfileMapServerEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.map.server.enabled");
}

std::optional<bool> isProfileMcpServerEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.mcp.server.enabled");
}

std::optional<bool> isProfileOppEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.opp.enabled");
}

std::optional<bool> isProfilePanNapEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.pan.nap.enabled");
}

std::optional<bool> isProfilePanPanuEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.pan.panu.enabled");
}

std::optional<bool> isProfilePbapClientEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.pbap.client.enabled");
}

std::optional<bool> isProfilePbapServerEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.pbap.server.enabled");
}

std::optional<bool> isProfileSapServerEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.sap.server.enabled");
}

std::optional<bool> isProfileCcpServerEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.ccp.server.enabled");
}

std::optional<bool> isProfileVcpControllerEnabled() {
    return GetProp<std::optional<bool>>("bluetooth.profile.vcp.controller.enabled");
}

}  // namespace android::sysprop::BluetoothProperties
c 复制代码
// Generated by the sysprop generator. DO NOT EDIT!

#pragma once

#include <cstdint>
#include <optional>
#include <string>
#include <vector>

namespace android::sysprop::BluetoothProperties {

enum class snoop_default_mode_values {
    EMPTY,
    DISABLED,
    FILTERED,
    FULL,
};

std::optional<snoop_default_mode_values> snoop_default_mode();
bool snoop_default_mode(const std::optional<snoop_default_mode_values>& value);

enum class snoop_log_mode_values {
    EMPTY,
    DISABLED,
    FILTERED,
    FULL,
};

std::optional<snoop_log_mode_values> snoop_log_mode();
bool snoop_log_mode(const std::optional<snoop_log_mode_values>& value);

std::optional<bool> factory_reset();
bool factory_reset(const std::optional<bool>& value);

std::optional<bool> isGapLePrivacyEnabled();

std::optional<std::string> getDefaultDeviceName();

std::vector<std::optional<std::uint32_t>> getClassOfDevice();

std::optional<std::int32_t> getHardwareOperatingVoltageMv();

std::optional<std::int32_t> getHardwareIdleCurrentMa();

std::optional<std::int32_t> getHardwareTxCurrentMa();

std::optional<std::int32_t> getHardwareRxCurrentMa();

std::optional<bool> isSupportPersistedStateEnabled();

std::optional<bool> isAdapterAddressValidationEnabled();

std::optional<bool> isProfileA2dpSinkEnabled();

std::optional<bool> isProfileA2dpSourceEnabled();

std::optional<bool> isProfileAshaCentralEnabled();

std::optional<bool> isProfileAvrcpControllerEnabled();

std::optional<bool> isProfileAvrcpTargetEnabled();

std::optional<bool> isProfileBapBroadcastAssistEnabled();

std::optional<bool> isProfileBapBroadcastSourceEnabled();

std::optional<bool> isProfileBapUnicastClientEnabled();

std::optional<bool> isProfileBasClientEnabled();

std::optional<bool> isProfileBassClientEnabled();

std::optional<bool> isProfileCsipSetCoordinatorEnabled();

std::optional<bool> isProfileGattEnabled();

std::optional<bool> isProfileHapClientEnabled();

std::optional<bool> isProfileHfpAgEnabled();

std::optional<bool> isProfileHfpHfEnabled();

std::optional<bool> isProfileHidDeviceEnabled();

std::optional<bool> isProfileHidHostEnabled();

std::optional<bool> isProfileMapClientEnabled();

std::optional<bool> isProfileMapServerEnabled();

std::optional<bool> isProfileMcpServerEnabled();

std::optional<bool> isProfileOppEnabled();

std::optional<bool> isProfilePanNapEnabled();

std::optional<bool> isProfilePanPanuEnabled();

std::optional<bool> isProfilePbapClientEnabled();

std::optional<bool> isProfilePbapServerEnabled();

std::optional<bool> isProfileSapServerEnabled();

std::optional<bool> isProfileCcpServerEnabled();

std::optional<bool> isProfileVcpControllerEnabled();

}  // namespace android::sysprop::BluetoothProperties

如何使用:
c 复制代码
// system/btif/src/btif_dm.cc

#include <android/sysprop/BluetoothProperties.sysprop.h>

static const char* btif_get_default_local_name() {
	...
    std::optional<std::string> default_local_name =
        android::sysprop::BluetoothProperties::getDefaultDeviceName();

	...
}

3. 各个属性使用场景介绍

列出了每个属性的 api_nameprop_name、类型、以及对应的典型使用场景和说明:

属性 API 名称 系统属性名 类型 使用场景描述
snoop_default_mode persist.bluetooth.btsnoopdefaultmode Enum (empty/disabled/filtered/full) 控制默认的 BT Snoop 日志记录模式(启动时默认设置)。用于决定是否及何种程度记录 Bluetooth HCI 日志,方便调试或抓包。
snoop_log_mode persist.bluetooth.btsnooplogmode Enum (empty/disabled/filtered/full) 实时控制当前的 BT Snoop 日志记录模式。可在运行时开启关闭日志,便于故障调试或日志采集。
factory_reset persist.bluetooth.factoryreset Boolean 用于触发 Bluetooth 模块的出厂重置行为。服务启动时检测该标志,进行清除配对记录或状态恢复。
isGapLePrivacyEnabled bluetooth.core.gap.le.privacy.enabled Boolean 决定是否在 BLE GAP 中启用隐私功能(RPA),在 Bluetooth 初始化时从 vendor overlay 读取,用于控制设备地址随机与否。
getDefaultDeviceName bluetooth.device.default_name String 指定设备默认蓝牙名称(如"Pixel 7")。Bluetooth 初始化时使用,决定配对名称显示。
getClassOfDevice bluetooth.device.class_of_device UIntList 指定蓝牙设备类型(如音频、输入设备等),初始化时使用设备类型分类,对其他设备展示能力信息。
getHardwareOperatingVoltageMv bluetooth.hardware.power.operating_voltage_mv Integer 指定蓝牙芯片的电压参数,用于功耗计算,如动态电源模型,初始化时读取。
getHardwareIdleCurrentMa bluetooth.hardware.power.idle_cur_ma Integer 指定空闲时的电流消耗,用于评估功耗性能指标。
getHardwareTxCurrentMa bluetooth.hardware.power.tx_cur_ma Integer 指定发送时的电流消耗,用于功耗模型评估。
getHardwareRxCurrentMa bluetooth.hardware.power.rx_cur_ma Integer 指定接收时的电流消耗,用于设备功耗分析。
isSupportPersistedStateEnabled bluetooth.framework.support_persisted_state Boolean 控制是否支持在重启后保持蓝牙配对状态、连接状态等。初始化时根据厂商覆盖设置行为。
isAdapterAddressValidationEnabled bluetooth.framework.adapter_address_validation Boolean 控制是否校验底层蓝牙地址有效性,初始化时决定是否验证 BLE/MAC 地址合法。
---所有 isProfile...Enabled 属性--- e.g. bluetooth.profile.a2dp.sink.enabled / .source / .gatt.enabled etc. Boolean 每个 Profile(A2DP、HFP、GATT、PBAP、AVRCP、HID、PAN 等)的开关:初始化时根据 overlay 配置决定 Framework 是否启用相应 Profile。用于裁剪系统功能和减小体积。

2. 我们该如何默认去配置呢:

上面这些 系统属性都是帮助我们来配置协议栈的, 我们可以在编译时对这些值进行默认的配置。

shell 复制代码
# disable avdtp delay report
PRODUCT_PRODUCT_PROPERTIES += \
    persist.bluetooth.disabledelayreports=true

# enable dual bluetooth
PRODUCT_PRODUCT_PROPERTIES += \
    persist.bluetooth.dual_adapter_mode=false

PRODUCT_PRODUCT_PROPERTIES += \
    bluetooth.profile.a2dp.source.enabled=true \
    bluetooth.profile.avrcp.target.enabled=true \
    bluetooth.profile.map.client.enabled=false \
    bluetooth.profile.pan.nap.enabled=false \
    bluetooth.profile.pan.panu.enabled=false \
    bluetooth.profile.hid.host.enabled=true \
    bluetooth.profile.hid.device.enabled=true \
    ro.bluetooth.av_role_switch.supported=true
  • packages/services/Car/car_product/properties/bluetooth.prop
c 复制代码
# The default Bluetooth Class of Device
# Service Field: 0x26 -> 38
#     - Bit 17: Networking
#     - Bit 18: Rendering
#     - Bit 21: Audio
# Major Class: 0x04 -> 4 (Audio / Video)
# Minor Class: 0x08 -> 8 (Car Audio)
bluetooth.device.class_of_device=38,4,8

# The Bluetooth profiles that cars expect to have enabled. All other profiles
# are disabled by default.
bluetooth.profile.a2dp.sink.enabled=true
bluetooth.profile.avrcp.controller.enabled=true
bluetooth.profile.gatt.enabled=true
bluetooth.profile.hfp.hf.enabled=true
bluetooth.profile.map.client.enabled=true
bluetooth.profile.pan.nap.enabled=true
bluetooth.profile.pan.panu.enabled=true
bluetooth.profile.pbap.client.enabled=true
相关推荐
用户2018792831673 小时前
如何利用AI工具快速学习Android源码
android
音视频牛哥5 小时前
Android 平台RTSP/RTMP播放器SDK接入说明
android·音视频·大牛直播sdk·rtsp播放器·rtmp播放器·rtmp低延迟播放·rtmpplayer
aningxiaoxixi6 小时前
Android Framework 之 AudioDeviceBroker
android·windows·ffmpeg
~Yogi6 小时前
今日学习:工程问题(场景题)
android·学习
移动开发者1号6 小时前
Android Activity状态保存方法
android·kotlin
移动开发者1号6 小时前
Volley源码深度分析与设计亮点
android·kotlin
张风捷特烈6 小时前
每日一题 Flutter#7,8 | 关于 State 两道简答题
android·flutter·面试
计蒙不吃鱼14 小时前
一篇文章实现Android图片拼接并保存至相册
android·java·前端
LucianaiB15 小时前
如何做好一份优秀的技术文档:专业指南与最佳实践
android·java·数据库