Bluetooth Log

0. Overview

蓝牙模块出现多种类型的Log:

  1. ALOGV(....);
  2. LOG_<log_level>, 如:LOG_VERBOSE(...);
  3. <module>_TRACE_<log_level>,如 APPL_TRACE_DEBUG(...);
  4. LOG(log_level) << ...;
  5. VLOG(log_level) << ...;

1. ALOGV

位于 liblog.so 库,引入 #include "utils/Log.h"#include <log/log.h> 头文件,即表明使用本类型的Log。

详见 Android Log - ALOGV
蓝牙模块仅 JNI 层使用了 ALOGV。
ALOGD、ALOGI、ALOGW、ALOGE 默认开启。

2. LOG_VERBOSE 原理

LOG_INFO, LOG_WARN, LOG_ERROR 默认开启。
LOG_VEROBSE 、LOG_DEBUG 2个需要配置开启

基于 liblog.so 库,自定义实现。

2.1 LOG_VEROBSE / LOG_DEBUG 实现

system/bt/gd/os/log.h

#pragma once

#include <cstdlib>

#ifndef LOG_TAG
#define LOG_TAG "bluetooth"
#endif

#if defined(OS_ANDROID)                // 1           OS_ANDROID

#include <log/log.h>

#include "common/init_flags.h"

#ifdef FUZZ_TARGET                      // 2            FUZZ_TARGET - if
#define LOG_VERBOSE(...)
#define LOG_DEBUG(...)
#define LOG_INFO(...)
#define LOG_WARN(...)
#else                                  // 2            FUZZ_TARGET - else

#define LOG_VERBOSE(fmt, args...)                                             \
  do {                                                                        \
    if (bluetooth::common::InitFlags::IsDebugLoggingEnabledForTag(LOG_TAG)) { \
      ALOGV("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args);          \
    }                                                                         \
  } while (false)

#define LOG_DEBUG(fmt, args...)                                               \
  do {                                                                        \
    if (bluetooth::common::InitFlags::IsDebugLoggingEnabledForTag(LOG_TAG)) { \
      ALOGD("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args);          \
    }                                                                         \
  } while (false)

#define LOG_INFO(fmt, args...) ALOGI("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)
#define LOG_WARN(fmt, args...) ALOGW("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)
#endif                                 // 2            FUZZ_TARGET - end
#define LOG_ERROR(fmt, args...) ALOGE("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)

#else  // 1
......
#endif /* defined(OS_ANDROID) */ // 1

  • 首先,由 // 2 可知:若定义了 FUZZ_TARGET ,那么 LOG_VERBOSE 会被关闭,因此这里不能定义 FUZZ_TARGET;
  • 其次,由 LOG_VERBOSE 定义可知,其由 ALOGV 实现,因此必须保证 ALOGV 已经开启,否则 LOG_VERBOSE 不会打印输出。开启方式可以参考Android Log - ALOGV
  • 再次,LOG_VERBOSE(LOG_DEBUG) 实现还依赖于 IsDebugLoggingvEnabledForTag(Android 12 开始出现,此版本之前没有这个函数去判断),下面分析该函数,其参数的 LOG_TAG 是 bluetooth
  • 最后,LOG_DEBUG 与 LOG_VERBOSE 的实现以及log level 控制基本相同,不同之处在于其依赖 ALOGD(默认开启,无需单独开启),不再赘述。

2.2 IsDebugLoggingvEnabledForTag 实现

分析 IsDebugLoggingvEnabledForTag 的调用流程,是分析其初始化的逆向,因此这里直接分析初始化流程,最终调用到 IsDebugLoggingvEnabledForTag 函数。

2.2.1 IsDebugLoggingvEnabledForTag 初始化流程

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java

public class AdapterService extends Service {

......
    @Override
    public void onCreate() {
......
        initNative(mUserManager.isGuestUser(), isCommonCriteriaMode(), configCompareResult,
                getInitFlags(), isAtvDevice);
......
    }
  • initNative(...) 将 getInitFlags() 传递到 Native 层,故先分析 getInitFlags() 。
    // Boolean flags
    private static final String GD_CORE_FLAG = "INIT_gd_core";
    private static final String GD_ADVERTISING_FLAG = "INIT_gd_advertising";
    private static final String GD_SCANNING_FLAG = "INIT_gd_scanning";
    private static final String GD_HCI_FLAG = "INIT_gd_hci";
    private static final String GD_CONTROLLER_FLAG = "INIT_gd_controller";
    private static final String GD_ACL_FLAG = "INIT_gd_acl";
    private static final String GD_L2CAP_FLAG = "INIT_gd_l2cap";
    private static final String GD_RUST_FLAG = "INIT_gd_rust";
    private static final String GD_LINK_POLICY_FLAG = "INIT_gd_link_policy";

   private static final String BTAA_HCI_LOG_FLAG = "INIT_btaa_hci";

    private static final String LOGGING_DEBUG_ENABLED_FOR_ALL_FLAG =
            "INIT_logging_debug_enabled_for_all";
    // String flags
    // Comma separated tags
    private static final String LOGGING_DEBUG_ENABLED_FOR_TAGS_FLAG =
            "INIT_logging_debug_enabled_for_tags";
    private static final String LOGGING_DEBUG_DISABLED_FOR_TAGS_FLAG =
            "INIT_logging_debug_disabled_for_tags";
 
    private String[] getInitFlags() {
        ArrayList<String> initFlags = new ArrayList<>();
        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH, GD_CORE_FLAG, false)) {
            initFlags.add(String.format("%s=%s", GD_CORE_FLAG, "true"));
        }
......
        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
                LOGGING_DEBUG_ENABLED_FOR_ALL_FLAG, false)) {
            initFlags.add(String.format("%s=%s", LOGGING_DEBUG_ENABLED_FOR_ALL_FLAG, "true"));
        }

        // Enabled list 由 ContentProvider 提供
        String debugLoggingEnabledTags = DeviceConfig.getString(DeviceConfig.NAMESPACE_BLUETOOTH,
                LOGGING_DEBUG_ENABLED_FOR_TAGS_FLAG, "");
        if (!debugLoggingEnabledTags.isEmpty()) {
            initFlags.add(String.format("%s=%s", LOGGING_DEBUG_ENABLED_FOR_TAGS_FLAG,
                    debugLoggingEnabledTags));
        }

        // Disabled list 由 ContentProvider 提供
        String debugLoggingDisabledTags = DeviceConfig.getString(DeviceConfig.NAMESPACE_BLUETOOTH,
                LOGGING_DEBUG_DISABLED_FOR_TAGS_FLAG, "");
        if (!debugLoggingDisabledTags.isEmpty()) {
            initFlags.add(String.format("%s=%s", LOGGING_DEBUG_DISABLED_FOR_TAGS_FLAG,
                    debugLoggingDisabledTags));
        }
......
        return initFlags.toArray(new String[0]);
    }
  • getInitFlags() 主要获取一个 key-value 的键值对的集合,该键值对决定 Log 的开关与否。
    1. 以上共有 10 个具体tag,2个组控制的tag,1个全局默认tag,它们的生效优先级关系:具体tag已设置,则以之为准;否则,查看组控制tag,若组控制tag未设置,则读取全局默认值。
  • DeviceConfig.getXxx() 说明该值由 ContentProvider 决定,具体值是多少、如何设置,后文(2.2.2)分析,这里先分析初始化流程。
static bool initNative(JNIEnv* env, jobject obj, jboolean isGuest,
                       jboolean isCommonCriteriaMode, int configCompareResult,
                       jobjectArray initFlags, jboolean isAtvDevice) {
......
  int flagCount = env->GetArrayLength(initFlags);
  jstring* flagObjs = new jstring[flagCount];
  const char** flags = nullptr;
  if (flagCount > 0) {
    flags = new const char*[flagCount + 1];
    flags[flagCount] = nullptr;
  }

  for (int i = 0; i < flagCount; i++) {
    flagObjs[i] = (jstring)env->GetObjectArrayElement(initFlags, i);
    flags[i] = env->GetStringUTFChars(flagObjs[i], NULL);
  }

  int ret = sBluetoothInterface->init(
      &sBluetoothCallbacks, isGuest == JNI_TRUE ? 1 : 0,
      isCommonCriteriaMode == JNI_TRUE ? 1 : 0, configCompareResult, flags,
      isAtvDevice == JNI_TRUE ? 1 : 0);
......
  return JNI_TRUE;
}

system/bt/btif/src/bluetooth.cc

static int init(bt_callbacks_t* callbacks, bool start_restricted,
                bool is_common_criteria_mode, int config_compare_result,
                const char** init_flags, bool is_atv) {
......
  bluetooth::common::InitFlags::Load(init_flags);
......
  return BT_STATUS_SUCCESS;
}

system/bt/gd/common/init_flags.h

#pragma once

#include <stdexcept>
#include <string>
#include <unordered_map>

#include "src/init_flags.rs.h"

namespace bluetooth {
namespace common {

class InitFlags final {
 public:
  static void Load(const char** flags);

  // 这里要求 tag 在列表中且值为 true,或 debug 全局开关已经打开
  inline static bool IsDebugLoggingEnabledForTag(const std::string& tag) {
    auto tag_setting = logging_debug_explicit_tag_settings.find(tag);
    if (tag_setting != logging_debug_explicit_tag_settings.end()) {
      return tag_setting->second;
    }
    return logging_debug_enabled_for_all;
  }
......

 private:
......
  static bool logging_debug_enabled_for_all;
  // save both log allow list and block list in the map to save hashing time
  static std::unordered_map<std::string, bool> logging_debug_explicit_tag_settings;
};
}  // namespace common
}  // namespace bluetooth
  • 由 IsDebugLoggingEnabledForTag(...) 函数可知,Log开关的开启有两个要求,满足一个要求即可:
    1. 指定的 tag 在显示指定了要开启的 LOG_TAG 列表(或);
    2. 不在指定列表中,但 debug 全局开关已经打开(或)。
      优先级关系:已设置具体tag开关,则以设置为准;未单独设置,则以默认值为准。

system/bt/gd/common/init_flags.cc

namespace bluetooth {
namespace common {

// 默认定义为 false,因此默认的 LOG_VORBOSE 处于关闭状态
bool InitFlags::logging_debug_enabled_for_all = false;
std::unordered_map<std::string, bool> InitFlags::logging_debug_explicit_tag_settings = {};


void InitFlags::Load(const char** flags) {
  const char** flags_copy = flags;

  // 重置
  SetAll(false);

  // 对所有的 key-value 字符串进行循环处理。
  while (flags != nullptr && *flags != nullptr) {

    // 以 = 切割字符串
    std::string flag_element = *flags;
    auto flag_pair = StringSplit(flag_element, "=", 2);
    if (flag_pair.size() != 2) {
      flags++;
      continue;
    }

    // 在列表中找到全局 key,并对其赋值
    ParseBoolFlag(flag_pair, "INIT_logging_debug_enabled_for_all", &logging_debug_enabled_for_all);

    // 在列表中找到 enabled key,将 tag 和 true 添加到集合中;
    if ("INIT_logging_debug_enabled_for_tags" == flag_pair[0]) {
      auto tags = StringSplit(flag_pair[1], ",");
      for (const auto& tag : tags) {
        auto setting = logging_debug_explicit_tag_settings.find(tag);
        if (setting == logging_debug_explicit_tag_settings.end()) {
          logging_debug_explicit_tag_settings.insert_or_assign(tag, true);
        }
      }
    }
    // 在列表中找到 disabled key,将 tag 和 false 添加到集合中;
    if ("INIT_logging_debug_disabled_for_tags" == flag_pair[0]) {
      auto tags = StringSplit(flag_pair[1], ",");
      for (const auto& tag : tags) {
        logging_debug_explicit_tag_settings.insert_or_assign(tag, false);
      }
    }
    flags++;
  }
......
}



void InitFlags::SetAll(bool value) {
  logging_debug_enabled_for_all = value;
  logging_debug_explicit_tag_settings.clear();
}
  • 由以上代码分析可知:logging_debug_enabled_for_alllogging_debug_explicit_tag_settings 由 AdapterService.java 中传入的 key-value 字符串决定,key 集合前文已述(具体名称、解析优先级等),后续分析 value 从何而来
2.2.2 DeviceConfig.getXxx(...)

frameworks/base/core/java/android/provider/DeviceConfig.java

    @SystemApi
    @RequiresPermission(READ_DEVICE_CONFIG)
    public static boolean getBoolean(@NonNull String namespace, @NonNull String name,
            boolean defaultValue) {
        String value = getProperty(namespace, name);
        return value != null ? Boolean.parseBoolean(value) : defaultValue;
    }

    @SystemApi
    @RequiresPermission(READ_DEVICE_CONFIG)
    public static String getString(@NonNull String namespace, @NonNull String name,
            @Nullable String defaultValue) {
        String value = getProperty(namespace, name);
        return value != null ? value : defaultValue;
    }



    @SystemApi
    @RequiresPermission(READ_DEVICE_CONFIG)
    public static String getProperty(@NonNull String namespace, @NonNull String name) {
        return getProperties(namespace, name).getString(name, null);
    }

由前文读取该值的源码可知,蓝牙模块的 namespace 是 "bluetooth"。

这里读写的数据库是 device_config,因此可以通过如下命令控制该log

adb shell device_config put bluetooth INIT_gd_core true
adb shell device_config put bluetooth INIT_gd_advertising true
adb shell device_config put bluetooth INIT_gd_scanning true
adb shell device_config put bluetooth INIT_gd_hci true
adb shell device_config put bluetooth INIT_gd_controller true
adb shell device_config put bluetooth INIT_gd_acl true
adb shell device_config put bluetooth INIT_gd_l2cap true
adb shell device_config put bluetooth INIT_gd_rust true
adb shell device_config put bluetooth INIT_gd_link_policy true

adb shell device_config put bluetooth INIT_btaa_hci true

// 未单独设置的tag,则使用 all 属性
adb shell device_config put bluetooth INIT_logging_debug_enabled_for_all true
// 单独关闭或开启log 的tag,优先级高于 all,低于单独设置
//adb shell device_config put bluetooth INIT_logging_debug_enabled_for_tags tags
//adb shell device_config put bluetooth INIT_logging_debug_disabled_for_tags tags

3. APPL_TRACE_DEBUG 原理

XXX_TRACE_WARNING、XXX_TRACE_ERROR 默认开启。
XXX_TRACE_VERBOSE、XXX_TRACE_DEBUG、XXX_TRACE_EVENT、XXX_TRACE_API 4个需要配置开启。

基于 liblog.so 库,自定义实现。

3.1 实现

system/bt/internal_include/bt_trace.h

/* Define trace levels */
typedef enum {
  BT_TRACE_LEVEL_NONE = 0,    /* No trace messages to be generated    */
  BT_TRACE_LEVEL_ERROR = 1,   /* Error condition trace messages       */
  BT_TRACE_LEVEL_WARNING = 2, /* Warning condition trace messages     */
  BT_TRACE_LEVEL_API = 3,     /* API traces                           */
  BT_TRACE_LEVEL_EVENT = 4,   /* Debug messages for events            */
  BT_TRACE_LEVEL_DEBUG = 5,   /* Full debug messages                  */
  BT_TRACE_LEVEL_VERBOSE = 6, /* Verbose debug messages               */
} tLEGACY_TRACE_LEVEL;

#define TRACE_TYPE_MASK 0x000000ff
#define TRACE_GET_TYPE(x) (((uint32_t)(x)) & TRACE_TYPE_MASK)

#define TRACE_TYPE_ERROR 0x00000000
#define TRACE_TYPE_WARNING 0x00000001
#define TRACE_TYPE_API 0x00000002
#define TRACE_TYPE_EVENT 0x00000003
#define TRACE_TYPE_DEBUG 0x00000004


// 初始 level 是 WARNING
#ifndef APPL_INITIAL_TRACE_LEVEL
#define APPL_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
#endif

/* define traces for application */
......
#define APPL_TRACE_EVENT(...)                                         \
  {                                                                   \
    if (appl_trace_level >= BT_TRACE_LEVEL_EVENT)                     \
      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
                 TRACE_TYPE_EVENT,                                    \
             ##__VA_ARGS__);                                          \
  }
#define APPL_TRACE_DEBUG(...)                                         \
  {                                                                   \
    if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG)                     \
      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
                 TRACE_TYPE_DEBUG,                                    \
             ##__VA_ARGS__);                                          \
  }
#define APPL_TRACE_VERBOSE(...)                                       \
  {                                                                   \
    if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)                   \
      LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
                 TRACE_TYPE_DEBUG,                                    \
             ##__VA_ARGS__);                                          \
  }


extern uint8_t appl_trace_level;

void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...);

system/bt/main/bte_logmsg.cc

void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {
  char buffer[BTE_LOG_BUF_SIZE];
  int trace_layer = TRACE_GET_LAYER(trace_set_mask); // 获取 layer,用于后文选择tag
  if (trace_layer >= TRACE_LAYER_MAX_NUM) trace_layer = 0;

  va_list ap;
  va_start(ap, fmt_str);
  vsnprintf(&buffer[MSG_BUFFER_OFFSET], BTE_LOG_MAX_SIZE, fmt_str, ap);
  va_end(ap);

#undef LOG_TAG
#define LOG_TAG bt_layer_tags[trace_layer]

  switch (TRACE_GET_TYPE(trace_set_mask)) {  // 获取前文设置的 log_level
    case TRACE_TYPE_ERROR:
      LOG_ERROR("%s", buffer);
      break;
    case TRACE_TYPE_WARNING:
      LOG_WARN("%s", buffer);
      break;
    case TRACE_TYPE_API:
    case TRACE_TYPE_EVENT:
      LOG_INFO("%s", buffer);
      break;
    case TRACE_TYPE_DEBUG:
      LOG_INFO("%s", buffer);
      break;
    default:
      /* we should never get this */
      LOG_ERROR("!BAD TRACE TYPE! %s", buffer);
      CHECK(TRACE_GET_TYPE(trace_set_mask) == TRACE_TYPE_ERROR);
      break;
  }
#undef LOG_TAG
#define LOG_TAG "bt_bte"
}

从以上内容可知:
APPL_TRACE_DEBUG 最终由 LOG_INFO (该level默认开启)实现,因此 APPL_TRACE_DEBUG 只需要关注自身设置的 log level 即可

该结论适用于 <module>_TRACE_<log_level> 所有module和 log_level。

3.2 Log level 实现

system/bt/main/bte_logmsg.cc

static void load_levels_from_config(const config_t* config) {
  CHECK(config != NULL);

  for (tBTTRC_FUNC_MAP* functions = &bttrc_set_level_map[0];
       functions->trc_name; ++functions) {
    int value = config_get_int(*config, CONFIG_DEFAULT_SECTION,
                               functions->trc_name, -1);
    if (value != -1) {
      functions->trace_level = value;
    }
    if (bluetooth::common::InitFlags::IsDebugLoggingEnabledForAll()) {
      LOG_INFO("Enable logging for %s because all debug logs are enabled",
               functions->trc_name);
      functions->trace_level = BT_TRACE_LEVEL_VERBOSE;
    }
    LOG_INFO("BTE_InitTraceLevels -- %s : Level %d", functions->trc_name,
             functions->trace_level);
    if (functions->p_f) functions->p_f(functions->trace_level);
  }
}

此处定义的所有模块,可以由 bt_stack.conf 文件来设置 log level,还可以通过前文的IsDebugLoggingEnabledForAll 函数来开启,若后者开启,则定义的所有模块打开 VERBOSE。

定义的模块定义如下(部分定义的模块不在此处,因此不能通过这里开启log):

static tBTTRC_FUNC_MAP bttrc_set_level_map[] = {
    {BTTRC_ID_STK_BTU, BTTRC_ID_STK_HCI, BTU_SetTraceLevel, "TRC_HCI",
     DEFAULT_CONF_TRACE_LEVEL},
    {BTTRC_ID_STK_L2CAP, BTTRC_ID_STK_L2CAP, L2CA_SetTraceLevel, "TRC_L2CAP",
     DEFAULT_CONF_TRACE_LEVEL},
    {BTTRC_ID_STK_RFCOMM, BTTRC_ID_STK_RFCOMM_DATA, PORT_SetTraceLevel,
     "TRC_RFCOMM", DEFAULT_CONF_TRACE_LEVEL},
    {BTTRC_ID_STK_AVDT, BTTRC_ID_STK_AVDT, AVDT_SetTraceLevel, "TRC_AVDT",
     DEFAULT_CONF_TRACE_LEVEL},
    {BTTRC_ID_STK_AVRC, BTTRC_ID_STK_AVRC, AVRC_SetTraceLevel, "TRC_AVRC",
     DEFAULT_CONF_TRACE_LEVEL},
    {BTTRC_ID_STK_A2DP, BTTRC_ID_STK_A2DP, A2DP_SetTraceLevel, "TRC_A2D",
     DEFAULT_CONF_TRACE_LEVEL},
#if (BNEP_INCLUDED == TRUE)
    {BTTRC_ID_STK_BNEP, BTTRC_ID_STK_BNEP, BNEP_SetTraceLevel, "TRC_BNEP",
     DEFAULT_CONF_TRACE_LEVEL},
#endif
    {BTTRC_ID_STK_BTM_ACL, BTTRC_ID_STK_BTM_SEC, BTM_SetTraceLevel, "TRC_BTM",
     DEFAULT_CONF_TRACE_LEVEL},
#if (HID_HOST_INCLUDED == TRUE)
    {BTTRC_ID_STK_HID, BTTRC_ID_STK_HID, HID_HostSetTraceLevel, "TRC_HID_HOST",
     DEFAULT_CONF_TRACE_LEVEL},
#endif
#if (PAN_INCLUDED == TRUE)
    {BTTRC_ID_STK_PAN, BTTRC_ID_STK_PAN, PAN_SetTraceLevel, "TRC_PAN",
     DEFAULT_CONF_TRACE_LEVEL},
#endif
    {BTTRC_ID_STK_SDP, BTTRC_ID_STK_SDP, SDP_SetTraceLevel, "TRC_SDP",
     DEFAULT_CONF_TRACE_LEVEL},
    {BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP",
     DEFAULT_CONF_TRACE_LEVEL},
#if (HID_DEV_INCLUDED == TRUE)
    {BTTRC_ID_STK_HIDD, BTTRC_ID_STK_HIDD, HID_DevSetTraceLevel, "TRC_HID_DEV",
     DEFAULT_CONF_TRACE_LEVEL},
#endif

    /* LayerIDs for BTA, currently everything maps onto appl_trace_level.
     */
    {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTAPP_SetTraceLevel, "TRC_BTAPP",
     DEFAULT_CONF_TRACE_LEVEL},
    {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTIF_SetTraceLevel, "TRC_BTIF",
     DEFAULT_CONF_TRACE_LEVEL},

    {0, 0, NULL, NULL, DEFAULT_CONF_TRACE_LEVEL}};

可根据模块、批量开启log或设置成某个 log level。bt_stack.conf 配置如下:

TRC_BTM=6
TRC_HCI=6
TRC_L2CAP=6
TRC_RFCOMM=6
TRC_OBEX=6
TRC_AVCT=6
TRC_AVDT=6
TRC_AVRC=6
TRC_AVDT_SCB=6
TRC_AVDT_CCB=6
TRC_A2D=6
TRC_SDP=6
TRC_SMP=6
TRC_BTAPP=6
TRC_BTIF=6
TRC_BNEP=6
TRC_PAN=6
TRC_HID_HOST=6
TRC_HID_DEV=6

4. LOG(log_level)

位于 libbase.so (基于 liblog.so),引入 #include <android-base/logging.h> 即表明使用本类型的Log。

LOG(INFO)、LOG(WARNING)、LOG(ERROR) 默认开启。
LOG(DEBUG)、LOG(VERBOSE) 2个需要配置开启

此处不详细分析
system/libbase/include/android-base/logging.h

enum LogSeverity {
  VERBOSE,
  DEBUG,
  INFO,
  WARNING,
  ERROR,
......
};
  1. 一般情况下,绝大多数的设备过滤器会过滤掉 VERBOSE 级别的log;
    可以通过 adb shell setprop log.tag.<TAG> V 命令打开指定 TAG 的 VERBOSE log。
  2. 一般情况下,该进程名称(adb shell ps -A 可以查看进程名称)作为 TAG;
    可以通过定义 LOG_TAG 宏 #define LOG_TAG xxx 来定义 TAG

可以自定义log写到何处(如 logcat、stderr、dmesg 等),不赘述。

5. VLOG(log_level)

位于 libchrome.so(基于 liblog.so),引入 #include <base/logging.h> 即表明使用本类型的Log。

此处不详细分析
external/libchrome/base/logging.h

typedef int LogSeverity;
const LogSeverity LOG_VERBOSE = -1;  // 用于 VLOG 模式

const LogSeverity LOG_INFO = 0;
const LogSeverity LOG_WARNING = 1;
const LogSeverity LOG_ERROR = 2;
const LogSeverity LOG_FATAL = 3;
......

#include <base/logging.h> 有三种 LOG 模式:

  1. 常规Log模式:LOG(INFO),LOG(WARNING)、LOG(ERROR) 、LOG(FATAL ),默认都是开启的,无需额外配置;

  2. DLOG 模式:Bluetooth没有用到,不分析。

  3. VLOG 模式:verbose logging 模式

    从头文件注释可知,verbose logging 的宏定义形如:
    VLOG(1) << ... ;
    VLOG(2) << ... ;
    verbose logging 可以按照模块打开log,
    例如:--vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0 的行为:

    • profile.h 或 profile.cc 将打印输出 VLOG(2) 及级别更低的log;
    • icon-loader.h 或 icon-loader.cc 将打印输出 VLOG(1)及级别更低的log;
    • browser 为前缀的文件打印输出VLOG(3)及级别更低的log;
    • chromeos 目录下的文件 将打印输出 VLOG(4) 及级别更低的log;
    • 其他内容将打印输出 VLOG(0) 及级别更新的log;

    Bluetooth模块可以在 bt_stack.conf 文件中配置以开启 verbose logging,
    比如:LoggingVModule=--vmodule=*/btm/*=6,*/btu/*=6,*/l2cap/*=6,*/gatt/*=6,*/hid/*=6,*/hf_client/*=6,*/smp/*=6,btm_ble_multi*=6,btif_*=6

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容