Android Log和Slog类详解--Android 12

本文详细介绍了Android系统中Log类和Slog类的实现,包括日志等级、buffer_id、主要成员方法以及JNI调用。Log类的打印主要涉及Log_ID_MAIN,而Slog使用Log_ID_SYSTEM。关键方法如__android_log_is_loggable用于判断日志是否可打印,__android_log_buf_write负责实际的日志写入。
摘要由CSDN通过智能技术生成

Log类的路径在/frameworks/base/core/java/android/util/Log.java

Slog类的路径在/frameworks/base/core/java/android/util/Slog.java


目录

一、Log的日志等级

二、Log日志打印的buffer_id

三、主要成员方法

四、JNI调用

五、system/logging/liblog下相关分析

1. 常见的枚举类android_LogPriority的定义

2. properties.cpp中的__android_log_is_loggable()

3. 常见的枚举类log_id的定义

4. __android_log_message结构体定义

5. logger_write.cpp中的__android_log_buf_write()

5. logger_write.cpp中的__android_log_write_log_message()


一、Log的日志等级

以下6个等级是Log日志对应的值,该level用来判断某一level的日志是否能打印,和native boolean isLoggable()相关。

//Priority constant for the println method; use Log.v.
public static final int VERBOSE = 2;
public static final int DEBUG = 3;
public static final int INFO = 4;
public static final int WARN = 5;
public static final int ERROR = 6;
public static final int ASSERT = 7;

二、Log日志打印的buffer_id

public static final int LOG_ID_MAIN = 0;
public static final int LOG_ID_RADIO = 1;
public static final int LOG_ID_EVENTS = 2;
public static final int LOG_ID_SYSTEM = 3;
public static final int LOG_ID_CRASH = 4;

三、主要成员方法

1. public static int v(String tag, String msg)

2. public static int d(String tag, String msg)

3. public static int i(String tag, String msg)

4. public static int w(String tag, String msg)

5. public static int e(String tag, String msg)

以上5个方法都是调用的print_native(),对于Log的各个level日志打印,他的日志打印bufferId使用Log_ID_MAIN。而SLOG各个level的日志打印也是调用的print_native(),只是它指定的bufferId使用Log_ID_SYSTEM

6. public static native boolean isLoggable(String tag, int level);

7. public static native int println_native(int bufID, int priority, String tag, String msg);

以上两个方法是Log日志打印的最核心的方法,他们是jni调用c++方法,具体参考【四、JNI调用】。

四、JNI调用

  1. isLoggable()和println_native()对应的jni文件在/frameworks/base/core/jni/android_util_Log.cpp中。
  2. Log类中isLoggable()对应的JNI方法是android_util_Log_isLoggable(),代码如下:
static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
{
    if (tag == NULL) {
        return false;
    }

    const char* chars = env->GetStringUTFChars(tag, NULL);
    if (!chars) {
        return false;
    }

    jboolean result = isLoggable(chars, level);

    env->ReleaseStringUTFChars(tag, chars);
    return result;
}

static jboolean isLoggable(const char* tag, jint level) {
    return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO);
}

该JNI方法最终调用/system/logging/liblog/properties.cpp中的__android_log_is_loggable()。该方法在第五部分介绍。

        3. Log类中println_native()对应android_util_Log_println_native()

该方法会先对msg、bufID、tag做校验,然后调用/system/logging/liblog/logger_write.cpp中的__android_log_buf_write()实现日志的write。

 int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);

        4. 通过JNINativeMethod动态注册JNI方法。

static const JNINativeMethod gMethods[] = {
    /* name, signature, funcPtr */
    { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
    { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
};
int register_android_util_Log(JNIEnv* env)
{
    //获取Log类
    jclass clazz = FindClassOrDie(env, "android/util/Log");
    //获取Log类中成员变量
    levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I"));
    levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I"));
    levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I"));
    levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I"));
    levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I"));
    levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));

    return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));
}

 该register_android_util_log()在AndroidRuntime.cpp中

static const RegJNIRec gRegJNI[] = {
    ...
    REG_JNI(register_android_util_Log),
    ...
}

五、system/logging/liblog下相关分析

1. 常见的枚举类android_LogPriority的定义

路径:/system/logging/liblog/include/android/log.h

typedef enum android_LogPriority {
  ANDROID_LOG_UNKNOWN = 0,
  ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
  ANDROID_LOG_VERBOSE,
  ANDROID_LOG_DEBUG,
  ANDROID_LOG_INFO,
  ANDROID_LOG_WARN,
  ANDROID_LOG_ERROR,
  ANDROID_LOG_FATAL,
  ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;

其中,minimum_log_priority默认值是ANDROID_LOG_DEFAULT,当然minimum_log_priority可以修改。ANDROID_LOG_DEFAULT默认level是ANDROID_LOG_INFO。


2. properties.cpp中的__android_log_is_loggable()

路径:/system/logging/liblog/properties.cpp

int __android_log_is_loggable(int prio, const char*, int) {
  int minimum_priority = __android_log_get_minimum_priority();
  if (minimum_priority == ANDROID_LOG_DEFAULT) {
    minimum_priority = ANDROID_LOG_INFO;
  }
  return prio >= minimum_priority;
}

判断当前prio等级的日志是否能打印,就是判断日志等级prio>=minimum_priority与否,大于最小level的日志均可以打印。

3. 常见的枚举类log_id的定义

路径:/system/logging/liblog/include/android/log.h

typedef enum log_id {
  LOG_ID_MIN = 0,

  /** The main log buffer. This is the only log buffer available to apps. */
  LOG_ID_MAIN = 0,
  LOG_ID_RADIO = 1,
  LOG_ID_EVENTS = 2,
  LOG_ID_SYSTEM = 3, /** The system log buffer. */
  LOG_ID_CRASH = 4,
  LOG_ID_STATS = 5,
  LOG_ID_SECURITY = 6, /** The security log buffer. */
  LOG_ID_KERNEL = 7, /** The kernel log buffer. */

  LOG_ID_MAX,
  LOG_ID_DEFAULT = 0x7FFFFFFF
} log_id_t;

 该结构体中的MINMAX长用来判断传入的日志bufferId是否有效。

4. __android_log_message结构体定义

路径:/system/logging/liblog/include/android/log.h

struct __android_log_message {
  /** Must be set to sizeof(__android_log_message) and is used for versioning. */
  size_t struct_size;
  int32_t buffer_id; /** {@link log_id_t} values. */
  int32_t priority; /** {@linkandroid_LogPriority} values. */
  const char* tag;
  const char* file; /** Optional file name, may be set to nullptr. */
  uint32_t line; /** Optional line number, ignore if file is nullptr. */
  const char* message;  /** The log message itself. */
};

5. logger_write.cpp中的__android_log_buf_write()

int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
  ErrnoRestorer errno_restorer;

  if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
    return -EPERM;
  }

  __android_log_message log_message = {
      sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, msg};
  __android_log_write_log_message(&log_message);
  return 1;
}
  • 首先调用__android_log_is_loggable()判断该等级prio的日志是否能打印;
  • 其次把参数封装成__android_log_message结构体的日志注意:此处结构体中const char* file = nullptr,所以Android原生系统的日志是在buffer中而不持久化文件中。
  • 最后调用__android_log_write_log_message()。

5. logger_write.cpp中的__android_log_write_log_message()

void __android_log_write_log_message(__android_log_message* log_message) {
  ErrnoRestorer errno_restorer;
  //对buffer_id判断有效性
  if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
      log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
      log_message->buffer_id != LOG_ID_CRASH) {
    return;
  }
  //如果tag为空,取默认TAG
  if (log_message->tag == nullptr) {
    log_message->tag = GetDefaultTag().c_str();
  }

#if __BIONIC__
  if (log_message->priority == ANDROID_LOG_FATAL) {
    android_set_abort_message(log_message->message);
  }
#endif
  //实际写日志的函数
  logger_function(log_message);
}
static __android_logger_function logger_function = __android_log_logd_logger;
void __android_log_logd_logger(const struct __android_log_message* log_message) {
  //把bufferID=LOG_ID_DEFAULT,赋值为LOG_ID_MAIN 
  int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;

  //构建iovec结构体数组,长度为3,分别保存日志priority、tag、message。
  struct iovec vec[3];
  vec[0].iov_base =
      const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
  vec[0].iov_len = 1;
  vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
  vec[1].iov_len = strlen(log_message->tag) + 1;
  vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
  vec[2].iov_len = strlen(log_message->message) + 1;
  //具体实现write log的函数
  write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
}
static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
  int ret;
  struct timespec ts;
  
  //不保存kernel日志
  if (log_id == LOG_ID_KERNEL) {
    return -EINVAL;
  }
  //获取系统时间
  clock_gettime(CLOCK_REALTIME, &ts);

  if (log_id == LOG_ID_SECURITY) {
    if (vec[0].iov_len < 4) {
      return -EINVAL;
    }

    ret = check_log_uid_permissions();
    if (ret < 0) {
      return ret;
    }
    if (!__android_log_security()) {
      /* If only we could reset downstream logd counter */
      return -EPERM;
    }
  } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
    if (vec[0].iov_len < 4) {
      return -EINVAL;
    }
  }

  ret = LogdWrite(log_id, &ts, vec, nr);
  PmsgWrite(log_id, &ts, vec, nr);

  return ret;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值