0. Overview
藍牙模塊出現(xiàn)多種類型的Log:
- ALOGV(....);
- LOG_<log_level>, 如:LOG_VERBOSE(...);
- <module>_TRACE_<log_level>,如 APPL_TRACE_DEBUG(...);
- LOG(log_level) << ...;
- 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 庫,自定義實現(xiàn)。
2.1 LOG_VEROBSE / LOG_DEBUG 實現(xiàn)
#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 實現(xiàn),因此必須保證 ALOGV 已經(jīng)開啟,否則 LOG_VERBOSE 不會打印輸出。開啟方式可以參考Android Log - ALOGV。
- 再次,LOG_VERBOSE(LOG_DEBUG) 實現(xiàn)還依賴于 IsDebugLoggingvEnabledForTag(Android 12 開始出現(xiàn),此版本之前沒有這個函數(shù)去判斷),下面分析該函數(shù),其參數(shù)的 LOG_TAG 是 bluetooth。
- 最后,LOG_DEBUG 與 LOG_VERBOSE 的實現(xiàn)以及l(fā)og level 控制基本相同,不同之處在于其依賴 ALOGD(默認開啟,無需單獨開啟),不再贅述。
2.2 IsDebugLoggingvEnabledForTag 實現(xiàn)
分析 IsDebugLoggingvEnabledForTag 的調用流程,是分析其初始化的逆向,因此這里直接分析初始化流程,最終調用到 IsDebugLoggingvEnabledForTag 函數(shù)。
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 的開關與否。
- 以上共有 10 個具體tag,2個組控制的tag,1個全局默認tag,它們的生效優(yōu)先級關系:具體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 全局開關已經(jīng)打開
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(...) 函數(shù)可知,Log開關的開啟有兩個要求,滿足一個要求即可:
- 指定的 tag 在顯示指定了要開啟的 LOG_TAG 列表(或);
- 不在指定列表中,但 debug 全局開關已經(jīng)打開(或)。
優(yōu)先級關系:已設置具體tag開關,則以設置為準;未單獨設置,則以默認值為準。
system/bt/gd/common/init_flags.cc
namespace bluetooth {
namespace common {
// 默認定義為 false,因此默認的 LOG_VORBOSE 處于關閉狀態(tài)
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 字符串進行循環(huán)處理。
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_all 、logging_debug_explicit_tag_settings 由 AdapterService.java 中傳入的 key-value 字符串決定,key 集合前文已述(具體名稱、解析優(yōu)先級等),后續(xù)分析 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"。
這里讀寫的數(shù)據(jù)庫是 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,優(yōu)先級高于 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 庫,自定義實現(xiàn)。
3.1 實現(xiàn)
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, ...);
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默認開啟)實現(xiàn),因此 APPL_TRACE_DEBUG 只需要關注自身設置的 log level 即可。
該結論適用于 <module>_TRACE_<log_level> 所有module和 log_level。
3.2 Log level 實現(xiàn)
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 函數(shù)來開啟,若后者開啟,則定義的所有模塊打開 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}};
可根據(jù)模塊、批量開啟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,
......
};
- 一般情況下,絕大多數(shù)的設備過濾器會過濾掉 VERBOSE 級別的log;
可以通過adb shell setprop log.tag.<TAG> V命令打開指定 TAG 的 VERBOSE log;
還可以通過在 xx/build.prop 文件添加log.tag.<TAG>=V來打開指定TAG 的 VERBOSE log。 - 一般情況下,該進程名稱(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 模式:
常規(guī)Log模式:LOG(INFO),LOG(WARNING)、LOG(ERROR) 、LOG(FATAL ),默認都是開啟的,無需額外配置;
DLOG 模式:Bluetooth沒有用到,不分析。
-
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