frameworks_bluetooth/service/utils/log_server.c

312 lines
8.9 KiB
C

/****************************************************************************
* Copyright (C) 2022 Xiaomi Corporation
*
* 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.
***************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <syslog.h>
#ifdef CONFIG_KVDB
#include <kvdb.h>
#endif
#include "bt_status.h"
#include "btsnoop_log.h"
#include "log.h"
#include "sal_interface.h"
#include "service_loop.h"
enum {
FRAMEWORK_LOG_LEVEL_CHANGED,
STACK_LOG_EN_CHANGED,
STACK_LOG_MASK_CHANGED,
SNOOP_LOG_EN_CHANGED,
};
#define PERSIST_BT_LOG_CHANGED "persist.bluetooth.log.changed"
#define PERSIST_BT_FRAMEWORK_LOG_LEVEL "persist.bluetooth.log.level"
#define PERSIST_BT_STACK_LOG_EN "persist.bluetooth.log.stack_enable"
#define PERSIST_BT_STACK_LOG_MASK "persist.bluetooth.log.stack_mask"
#define PERSIST_BT_SNOOP_LOG_EN "persist.bluetooth.log.snoop_enable"
// #define PERSIST_BT_SNOOP_LOG_CID_MASK "persist.bluetooth.log.snoop_cid_mask"
// #define PERSIST_BT_SNOOP_LOG_PKT_MASK "persist.bluetooth.log.snoop_pkt_mask"
struct bt_logger {
uint8_t stack_enable;
uint8_t snoop_enable;
uint8_t framework_level;
int stack_mask;
int snoop_cid_mask;
int snoop_pkt_mask;
int monitor_fd;
service_poll_t* poll;
};
static struct bt_logger g_logger = { 0, 0, BT_LOG_LEVEL_OFF, 0, 0, 0, -1 };
static const char* log_id_str(uint8_t id)
{
switch (id) {
case LOG_ID_SNOOP:
return "SNOOP";
case LOG_ID_STACK:
return "STACK";
case LOG_ID_FRAMEWORK:
return "FRAMEWORK";
default:
return "";
}
}
static uint8_t bt_log_set_level(uint8_t level, bool changed)
{
if (level != BT_LOG_LEVEL_OFF && level != BT_LOG_LEVEL_ERROR && level != BT_LOG_LEVEL_WARNING && level != BT_LOG_LEVEL_INFO && level != BT_LOG_LEVEL_DEBUG)
return g_logger.framework_level;
g_logger.framework_level = level;
#if defined(CONFIG_KVDB) && defined(__NuttX__)
if (!changed) {
property_set_int32(PERSIST_BT_FRAMEWORK_LOG_LEVEL, level);
property_commit();
}
#endif
syslog(LOG_INFO, "framework log level: %d\n", g_logger.framework_level);
return g_logger.framework_level;
}
static int stack_log_setup(void)
{
if (bt_sal_debug_enable() != BT_STATUS_SUCCESS) {
syslog(LOG_ERR, "%s\n", "stack log not support");
return -1;
}
if (bt_sal_debug_update_log_mask(g_logger.stack_mask) != BT_STATUS_SUCCESS) {
syslog(LOG_ERR, "%s\n", "stack log mask update fail");
bt_sal_debug_disable();
return -1;
}
return 0;
}
void bt_log_module_enable(int id, bool changed)
{
const char* property = NULL;
syslog(LOG_DEBUG, "%s, id %d\n", __func__, id);
switch (id) {
case LOG_ID_SNOOP: {
if (g_logger.snoop_enable)
return;
if (btsnoop_log_enable() != BT_STATUS_SUCCESS) {
syslog(LOG_ERR, "%s\n", "enable snoop log fail");
return;
}
g_logger.snoop_enable = 1;
property = PERSIST_BT_SNOOP_LOG_EN;
break;
}
case LOG_ID_STACK: {
if (g_logger.stack_enable)
return;
if (stack_log_setup() != 0)
return;
g_logger.stack_enable = 1;
property = PERSIST_BT_STACK_LOG_EN;
break;
}
case LOG_ID_FRAMEWORK: {
return;
}
}
#if defined(CONFIG_KVDB) && defined(__NuttX__)
if (!changed) {
property_set_int32(property, 1);
property_commit();
}
#endif
syslog(LOG_INFO, "%s enabled\n", log_id_str(id));
}
void bt_log_module_disable(int id, bool changed)
{
const char* property = NULL;
syslog(LOG_DEBUG, "%s id %d\n", __func__, id);
switch (id) {
case LOG_ID_SNOOP: {
if (!g_logger.snoop_enable)
return;
btsnoop_log_disable();
g_logger.snoop_enable = 0;
property = PERSIST_BT_SNOOP_LOG_EN;
break;
}
case LOG_ID_STACK: {
if (!g_logger.stack_enable)
return;
bt_sal_debug_disable();
g_logger.stack_enable = 0;
property = PERSIST_BT_STACK_LOG_EN;
break;
}
case LOG_ID_FRAMEWORK: {
g_logger.framework_level = BT_LOG_LEVEL_OFF;
return;
}
}
#if defined(CONFIG_KVDB) && defined(__NuttX__)
if (!changed) {
property_set_int32(property, 0);
property_commit();
}
#endif
syslog(LOG_INFO, "%s disabled\n", log_id_str(id));
}
#if defined(CONFIG_KVDB) && defined(__NuttX__)
static void property_monitor_cb(service_poll_t* poll,
int revent, void* userdata)
{
if (revent & POLL_ERROR || revent & POLL_DISCONNECT) {
service_loop_remove_poll(g_logger.poll);
g_logger.poll = NULL;
if (g_logger.monitor_fd)
property_monitor_close(g_logger.monitor_fd);
g_logger.monitor_fd = -1;
} else if (revent & POLL_READABLE) {
int changed = 0;
char key[PROP_NAME_MAX];
int new;
property_monitor_read(g_logger.monitor_fd, key, &changed, sizeof(changed));
if (changed & (1 << FRAMEWORK_LOG_LEVEL_CHANGED)) {
new = property_get_int32(PERSIST_BT_FRAMEWORK_LOG_LEVEL, 0);
if (new != g_logger.framework_level)
bt_log_set_level(new, true);
}
if (changed & (1 << STACK_LOG_EN_CHANGED)) {
new = property_get_int32(PERSIST_BT_STACK_LOG_EN, 0);
if (new != g_logger.stack_enable) {
if (new)
bt_log_module_enable(LOG_ID_STACK, true);
else
bt_log_module_disable(LOG_ID_STACK, true);
}
}
if (changed & (1 << STACK_LOG_MASK_CHANGED)) {
new = property_get_int32(PERSIST_BT_STACK_LOG_MASK, 0);
if (new != g_logger.stack_mask) {
g_logger.stack_mask = new;
bt_sal_debug_update_log_mask(g_logger.stack_mask);
}
}
if (changed & (1 << SNOOP_LOG_EN_CHANGED)) {
new = property_get_int32(PERSIST_BT_SNOOP_LOG_EN, 0);
if (new != g_logger.snoop_enable) {
if (new)
bt_log_module_enable(LOG_ID_SNOOP, true);
else
bt_log_module_disable(LOG_ID_SNOOP, true);
}
}
}
}
#endif
void bt_log_server_init(void)
{
#if defined(CONFIG_KVDB) && defined(__NuttX__)
/** framework log init */
g_logger.framework_level = property_get_int32(PERSIST_BT_FRAMEWORK_LOG_LEVEL, DEFAULT_BT_LOG_LEVEL);
/** stack log init */
bt_sal_debug_init();
g_logger.stack_enable = property_get_int32(PERSIST_BT_STACK_LOG_EN, 0);
g_logger.stack_mask = property_get_int32(PERSIST_BT_STACK_LOG_MASK, 0);
if (g_logger.stack_enable)
stack_log_setup();
/** snoop log init */
if (btsnoop_log_init() != BT_STATUS_SUCCESS)
syslog(LOG_ERR, "init snoop log fail\n");
g_logger.snoop_enable = property_get_int32(PERSIST_BT_SNOOP_LOG_EN, 0);
if (g_logger.snoop_enable) {
if (btsnoop_log_enable() != BT_STATUS_SUCCESS)
syslog(LOG_ERR, "%s\n", "enable snoop log fail");
}
/** start log property monitor */
property_set_int32(PERSIST_BT_LOG_CHANGED, 0);
g_logger.monitor_fd = property_monitor_open(PERSIST_BT_LOG_CHANGED);
if (g_logger.monitor_fd < 0) {
syslog(LOG_ERR, "propert monitor open fail: %d\n", errno);
return;
}
g_logger.poll = service_loop_poll_fd(g_logger.monitor_fd, POLL_READABLE, property_monitor_cb, NULL);
if (g_logger.poll == NULL)
syslog(LOG_ERR, "%s\n", "propert monitor poll error");
syslog(1, "Framework log level: %d, Stack:%d, mask:%08x, Snoop: %d\n", g_logger.framework_level,
g_logger.stack_enable, g_logger.stack_mask, g_logger.snoop_enable);
#else
#endif
}
void bt_log_server_cleanup(void)
{
/** stop log property monitor */
service_loop_remove_poll(g_logger.poll);
g_logger.poll = NULL;
if (g_logger.monitor_fd)
property_monitor_close(g_logger.monitor_fd);
g_logger.monitor_fd = -1;
/** snoop log deinit */
if (g_logger.snoop_enable)
btsnoop_log_disable();
btsnoop_log_uninit();
/** stack log deinit */
if (g_logger.stack_enable)
bt_sal_debug_disable();
bt_sal_debug_cleanup();
}
bool bt_log_print_check(uint8_t level)
{
if (g_logger.framework_level < level || g_logger.framework_level == BT_LOG_LEVEL_OFF)
return false;
return true;
}