【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
相关推荐
祖国的好青年4 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴5 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭5 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首5 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
zhangphil6 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙6 小时前
echarts,3d堆叠图
android·3d·echarts
李白的天不白7 小时前
如何项目发布到github上
android·vue.js
summerkissyou19877 小时前
Android-RTC、NTP 和 System Time(系统时间)
android
小书房7 小时前
Kotlin使用体验及理解1
android·开发语言·kotlin
撩得Android一次心动8 小时前
Android Navigation 组件全面讲解
android·jetpack·navigation