AndroidT(13) Log 系统 -- C 语言格式的LOG输出(一)

本文介绍了Android中C语言风格log接口ALOG系列的使用,包括log内容所属的类型(main、system、radio)和级别(VERBOSE、DEBUG、INFO、WARN、ERROR、FATAL),并提供了一个示例代码和如何通过属性控制log级别。

1.概览

  c语言中的printf我想大家都非常的熟悉了,他的基本格式如下

int printf(const char *format, ...);

  前半部分 format 指向的字符串用于描述最终输出内容的格式,而后半部分则是被前面 format 所解析的各种变量/常量,这两部分则是构成输出的内容。而Android中也有类似的内容输出函数,用法和printf也是类似的及前半部为格式,后半部为各种变量/常量。

ALOGI(const char *format, ...);

  printf打印内容到标准输出,而ALOG系列接口则是打印内容到Android的log系统中去。

2.打印LOG内容所属的类型

  在 Android 中,有着非常多的子系统,所以 Android 的 ALOG 系统是支持多个buffer的,即不同类型的log写入不同的buffer中。它所支持的log类型可以简单的使用对应版本的 logcat 工具查看

board:/ # logcat -h
Usage: logcat [options] [filterspecs]

General options:
  -b, --buffer=<buffer>       Request alternate ring buffer(s):
                                main system radio events crash default all
                              Additionally, 'kernel' for userdebug and eng builds, and
                              'security' for Device Owner installations.
                              Multiple -b parameters or comma separated list of buffers are
                              allowed. Buffers are interleaved.
                              Default -b main,system,crash,kernel.

  在c语言风格的log接口中大致支持3种buffer,它们分别是 main/system/radio ,在使用的时候只要包含 liblog::log/log.h 即可

2.1 main 类型

  main类型的的buffer用来打印一般的log信息,注意了,虽然是一般,但是也不要打印垃圾内容,毕竟log系统的buffer是很紧俏的。

//system\logging\liblog\include\log\log_main.h
#define ALOGI(const char *format, ...)

2.2 system 类型

  该类型的 buffer 用来打印系统组件相关的log。同样的不要打印垃圾信息到这一类型的buffer中去。

//system\logging\liblog\include\log\log_system.h
#define SLOGI(const char *format, ...)

2.3 radio 类型

  该类型的 buffer 用来打印电话相关的组件的log。同样的不要打印垃圾信息到这一类型的buffer中去。

//system\logging\liblog\include\log\log_radio.h
#define RLOGI(const char *format, ...)

3.打印内容所属的级别

  手头需要做的事有轻重缓急,log中的信息所代表的事项也同样如此。下面是Android log 系统的几个级别

//file:system\logging\liblog\include\android\log.h
/**
 * Android log priority values, in increasing order of priority.
 */
typedef enum android_LogPriority {
    ...
  /** Verbose logging. Should typically be disabled for a release apk. */
  ANDROID_LOG_VERBOSE,
  /** Debug logging. Should typically be disabled for a release apk. */
  ANDROID_LOG_DEBUG,
  /** Informational logging. Should typically be disabled for a release apk. */
  ANDROID_LOG_INFO,
  /** Warning logging. For use with recoverable failures. */
  ANDROID_LOG_WARN,
  /** Error logging. For use with unrecoverable failures. */
  ANDROID_LOG_ERROR,
  /** Fatal logging. For use when aborting. */
  ANDROID_LOG_FATAL,
  ...
} android_LogPriority;

  每一个级别的使用场景在代码注释中说的也算详细,此处就不再赘述。其中 ANDROID_LOG_FATAL 级别的LOG最终会调用 abort,abort则会造成应用程序的意外退出。如果在非系统应用中则会导致应用本身退出。如果是系统级别的那么就有可能导致Android系统奔溃了

NAME
       abort - cause abnormal process termination

SYNOPSIS
       #include <stdlib.h>

       void abort(void);

DESCRIPTION
       The  abort() first unblocks the SIGABRT signal, and then raises that signal for the calling process (as though raise(3) was called).  This results in
       the abnormal termination of the process unless the SIGABRT signal is caught and the signal handler does not return (see longjmp(3)).

       If the abort() function causes process termination, all open streams are closed and flushed.

       If the SIGABRT signal is ignored, or caught by a handler that returns, the abort() function will still  terminate  the  process.   It  does  this  by
       restoring the default disposition for SIGABRT and then raising the signal for a second time.

RETURN VALUE
       The abort() function never returns.

3.1 VERBOSE 级别

//system\logging\liblog\include\log\log_main.h
#define ALOGV(const char *format, ...)
//system\logging\liblog\include\log\log_radio.h
#define RLOGV(const char *format, ...)
//system\logging\liblog\include\log\log_system.h
#define SLOGV(const char *format, ...)

3.2 DEBUG 级别

//system\logging\liblog\include\log\log_main.h
#define ALOGD(const char *format, ...)
//system\logging\liblog\include\log\log_radio.h
#define RLOGD(const char *format, ...)
//system\logging\liblog\include\log\log_system.h
#define SLOGD(const char *format, ...)

3.3 INFO 级别

//system\logging\liblog\include\log\log_main.h
#define ALOGI(const char *format, ...)
//system\logging\liblog\include\log\log_radio.h
#define RLOGI(const char *format, ...)
//system\logging\liblog\include\log\log_system.h
#define SLOGI(const char *format, ...)

3.4 WARN 级别

//system\logging\liblog\include\log\log_main.h
#define ALOGW(const char *format, ...)
//system\logging\liblog\include\log\log_radio.h
#define RLOGW(const char *format, ...)
//system\logging\liblog\include\log\log_system.h
#define SLOGW(const char *format, ...)

3.5 ERROR 级别

//system\logging\liblog\include\log\log_main.h
#define ALOGE(const char *format, ...)
//system\logging\liblog\include\log\log_radio.h
#define RLOGE(const char *format, ...)
//system\logging\liblog\include\log\log_system.h
#define SLOGE(const char *format, ...)

3.6 FATAL 级别

//system\logging\liblog\include\log\log_main.h
ALOG(LOG_FATAL, LOG_TAG, const char *format, ...);

4.使用示例 – ALOGtest

4.1 编译配置 – Android.bp

cc_binary {
    name: "ALOGtest",
    srcs: [
        "*.cpp",
    ],
    shared_libs: [
        "liblog",
    ],
    cppflags: [
        "-Wno-unused-parameter",
    ],
}

  C语言风格的log打印接口,只使用了库 liblog,所以只要包含它即可。

4.2 测试源码 – ALOGtest.cpp

//ALOGtest.cpp

#define LOG_TAG     "ALOGtest"

#include <stdlib.h>
#include <log/log.h>//from liblog

/**
 * board:/ # logcat -b all -s ALOGtest&
 * board:/ # ALOGtest
 * board:/ # --------- beginning of main
 * 11-27 14:40:09.361  5863  5863 I ALOGtest: ALOGI:write INFO level to main buffer
 * 11-27 14:40:09.362  5863  5863 I ALOGtest: ALOGI_IF:write INFO level to main buffer
 * --------- beginning of radio
 * 11-27 14:40:09.362  5863  5863 I ALOGtest: RLOGI:write INFO level to radio buffer
 * 11-27 14:40:09.362  5863  5863 I ALOGtest: RLOGI_IF:write INFO level to radio buffer
 * --------- beginning of system
 * 11-27 14:40:09.362  5863  5863 I ALOGtest: SLOGI:write INFO level to sytem buffer
 * 11-27 14:40:09.362  5863  5863 I ALOGtest: SLOGI_IF:write INFO level to sytem buffer
*/

int main(int argc, char* argv[])
{
    /*
        logcat -b main -s ALOGtest&
    */
    ALOGI("ALOGI:write INFO level to main buffer\n");
    ALOGI_IF((3 > 2), "ALOGI_IF:write INFO level to main buffer\n");
    /*
        logcat -b radio -s ALOGtest&
    */
    RLOGI("RLOGI:write INFO level to radio buffer\n");
    RLOGI_IF((3 > 2), "RLOGI_IF:write INFO level to radio buffer\n");
    /*
        logcat -b system -s ALOGtest&
    */
    SLOGI("SLOGI:write INFO level to sytem buffer\n");
    SLOGI_IF((3 > 2), "SLOGI_IF:write INFO level to sytem buffer\n");

    /**
     * board:/ # ALOGtest
     * 11-27 16:04:54.597  5883  5883 I ALOGtest: ALOGI:write INFO level to main buffer
     * 11-27 16:04:54.597  5883  5883 I ALOGtest: ALOGI_IF:write INFO level to main buffer
     * 11-27 16:04:54.597  5883  5883 I ALOGtest: RLOGI:write INFO level to radio buffer
     * 11-27 16:04:54.597  5883  5883 I ALOGtest: RLOGI_IF:write INFO level to radio buffer
     * 11-27 16:04:54.597  5883  5883 I ALOGtest: SLOGI:write INFO level to sytem buffer
     * 11-27 16:04:54.598  5883  5883 I ALOGtest: SLOGI_IF:write INFO level to sytem buffer
     * 11-27 16:04:54.598  5883  5883 F ALOGtest: ALOG:LOG_FATAL:write LOG_FATAL level to main buffer
    */
    ALOG(LOG_FATAL, LOG_TAG, "ALOG:LOG_FATAL:write LOG_FATAL level to main buffer\n");
    return EXIT_SUCCESS;
}

  LOG_TAG需要在log/log.h前定义。
  所有支持的接口都位于如下接口

file:system\logging\liblog\include\log\log.h

5.运行结果

board:/ # ALOGtest
11-27 16:15:05.936  5885  5885 I ALOGtest: ALOGI:write INFO level to main buffer
11-27 16:15:05.937  5885  5885 I ALOGtest: ALOGI_IF:write INFO level to main buffer
11-27 16:15:05.937  5885  5885 I ALOGtest: RLOGI:write INFO level to radio buffer
11-27 16:15:05.937  5885  5885 I ALOGtest: RLOGI_IF:write INFO level to radio buffer
11-27 16:15:05.937  5885  5885 I ALOGtest: SLOGI:write INFO level to sytem buffer
11-27 16:15:05.938  5885  5885 I ALOGtest: SLOGI_IF:write INFO level to sytem buffer
11-27 16:15:05.938  5885  5885 F ALOGtest: ALOG:LOG_FATAL:write LOG_FATAL level to main buffer

6.使用属性控制log级别输出

  Android log子系统也提供了通过属性来控制log级别的输出,格式如下

adb shell setprop log.tag.<TAG> <LEVEL>

LEVEL:
    V
    D
    I
    W
    E
    F

  其中的TAG就是我们代码中设置的LOG_TAG

board:/ # setprop log.tag.ALOGtest F
board:/ # ALOGtest
11-27 16:18:10.801  5888  5888 F ALOGtest: ALOG:LOG_FATAL:write LOG_FATAL level to main buffer
board:/ # setprop log.tag.ALOGtest V
board:/ # ALOGtest
11-27 16:22:18.811  5891  5891 I ALOGtest: ALOGI:write INFO level to main buffer
11-27 16:22:18.812  5891  5891 I ALOGtest: ALOGI_IF:write INFO level to main buffer
11-27 16:22:18.812  5891  5891 I ALOGtest: RLOGI:write INFO level to radio buffer
11-27 16:22:18.812  5891  5891 I ALOGtest: RLOGI_IF:write INFO level to radio buffer
11-27 16:22:18.812  5891  5891 I ALOGtest: SLOGI:write INFO level to sytem buffer
11-27 16:22:18.812  5891  5891 I ALOGtest: SLOGI_IF:write INFO level to sytem buffer
11-27 16:22:18.812  5891  5891 F ALOGtest: ALOG:LOG_FATAL:write LOG_FATAL level to main buffer
<think>我们正在处理个复杂的命令序列,涉及多个步骤:切换目录、初始化环境、选择编译配置和编译内核组件。命令如下: cd /home/zhujianhua/work/AndroidU/sprd_vnd/bsp && source build/envsetup.sh && lunch ums9230_6h10_Natv_k515 - userdebug - androidt && make kernelcomponent -j3 我们将分解这个命令,并解释每个部分的作用,然后讨论可能遇到的问题及解决办法。 ## 命令分解 1. **cd /home/zhujianhua/work/AndroidU/sprd_vnd/bsp** 切换到指定目录,这是后续命令执行的工作目录。 2. **source build/envsetup.sh** 执行`build/envsetup.sh`脚本,该脚本用于初始化Android编译环境。它会定义些有用的函数(如`lunch`、`m`、`mm`等)并设置环境变量。 3. **lunch ums9230_6h10_Natv_k515 - userdebug - androidt** 选择编译目标(target)。`lunch`命令用于从菜单中选择或直接指定个目标。这里直接指定目标为`ums9230_6h10_Natv_k515 - userdebug - androidt`。 注意:目标字符串中包含了空格和连字符,这可能是笔误?通常,`lunch`的目标格式为`<product_name>-<build_variant>`,例如`aosp_arm-eng`。因此,这里的目标应该是个整体字符串,可能应为`ums9230_6h10_Natv_k515-userdebug-androidt`(用连字符连接,无空格)。如果目标字符串包含空格,可能会导致`lunch`命令无法识别。 4. **make kernelcomponent -j3** 开始编译名为`kernelcomponent`的目标,使用3个并行任务(`-j3`)。这可能是特定于该平台的编译目标。 ## 可能遇到的问题及解决方法 ### 1. 目录不存在或路径错误 - **问题**:如果`/home/zhujianhua/work/AndroidU/sprd_vnd/bsp`目录不存在,`cd`命令会失败,整个命令链会终止(因为使用了`&&`,前个命令失败则后续不执行)。 - **解决**:确保该目录存在,并且路径正确。可以使用`ls`命令检查目录是否存在。 ### 2. envsetup.sh 脚本不存在 - **问题**:在切换目录后,如果`build/envsetup.sh`文件不存在,`source`命令会失败。 - **解决**:确认该目录下存在`build`子目录,并且`envsetup.sh`位于其中。通常,在Android源代码树的根目录下会有这个文件。因此,请确认当前工作目录(`/home/zhujianhua/work/AndroidU/sprd_vnd/bsp`)是否是正确的Android源代码根目录(或包含`build`目录的目录)。 ### 3. lunch 目标无效 - **问题**:目标字符串`ums9230_6h10_Natv_k515 - userdebug - androidt`包含空格,这可能导致`lunch`命令无法识别。正确的目标格式通常不包含空格,而是用连字符连接各个部分。 - **解决**:检查目标名称的正确性。可能应为`ums9230_6h10_Natv_k515-userdebug-androidt`(去掉空格)。可以通过运行`lunch`命令然后按空格键列出所有可选目标,查看正确的目标名称。 ### 4. 编译目标 kernelcomponent 不存在 - **问题**:如果`kernelcomponent`不是个有效的编译目标,`make`命令会失败。 - **解决**:确认该目标在当前的编译环境中存在。可以尝试先运行`make`命令查看所有目标,或者查阅项目文档。另外,有时目标名称可能有拼写错误,注意检查。 ### 5. 编译失败 - **问题**:编译过程中可能因为各种原因失败(如依赖缺失、代码错误、环境配置不正确等)。 - **解决**: - 检查错误日志,确定失败原因。 - 确保所有必要的依赖已经安装(如编译器、库文件等)。 - 尝试使用更少的并行任务(例如`-j1`)来避免并行编译中的问题。 - 清理编译环境(如运行`make clean`)然后重新编译。 ### 6. 环境变量未正确设置 - **问题**:在`source build/envsetup.sh`和`lunch`之后,环境变量(如`ANDROID_PRODUCT_OUT`等)可能没有正确设置,导致编译失败。 - **解决**:在运行`lunch`后,可以打印环境变量(如`echo $TARGET_PRODUCT`)来验证设置是否正确。 ### 7. 并行编译选项-j3的问题 - **问题**:使用`-j3`指定3个并行任务,但有时并行编译可能导致竞争条件或资源不足(内存不足等)。 - **解决**:根据机器配置调整并行任务数。通常建议设置为CPU核心数的1.5到2倍。如果编译失败,尝试减少并行任务数(如`-j1`)以排除并行引起的问题。 ## 建议的执行步骤 1. 首先,单独执行每个命令,检查每步是否成功。 ```bash cd /home/zhujianhua/work/AndroidU/sprd_vnd/bsp source build/envsetup.sh lunch ums9230_6h10_Natv_k515-userdebug-androidt # 注意去掉空格 make kernelcomponent -j3 ``` 2. 如果`lunch`的目标格式有问题,请使用正确的目标字符串。 3. 如果编译失败,查看错误输出,并逐步排查。 ## 相关帮助命令 - 查看`lunch`的帮助:运行`lunch`后直接回车,会列出所有可选目标。 - 查看`make`的帮助:`make -h` 或 `make --help`,但注意在Android编译环境中,也可以使用`m -h`(在`envsetup.sh`之后可用)。 - 编译单个模块:`mmm <模块路径>` 或 `mm`(在模块目录下)可以在`envsetup.sh`之后使用。 希望这些信息能帮助你顺利执行命令! §§相关问题§§ 1. 如何验证Android编译环境的正确设置? 2. 在编译过程中遇到依赖错误应该如何解决? 3. 如何增加或减少并行编译任务数,以及如何确定最佳任务数? </think>我将针对您提供的命令序列,分析各个步骤的作用、可能遇到的问题及解决方案,并提供相关帮助信息。 ### 命令分解与作用 ```bash cd /home/zhujianhua/work/AndroidU/sprd_vnd/bsp && source build/envsetup.sh && lunch ums9230_6h10_Natv_k515-userdebug-androidt && make kernelcomponent -j3 ``` 1. **`cd .../bsp`** 切换到Android源码目录(展锐平台特定路径) 2. **`source build/envsetup.sh`** 初始化Android编译环境: - 添加`lunch`、`m`、`mm`等编译命令 - 设置环境变量(如`ANDROID_BUILD_PATHS`) - 注册产品配置信息[^1] 3. **`lunch ...`** 选择目标设备编译配置: - `ums9230_6h10_Natv_k515`:芯片平台型号 - `userdebug`:编译类型(可调试版本) - `androidt`:Android版本分支 4. **`make kernelcomponent -j3`** 编译内核组件: - `-j3`:使用3线程并行编译 ### 常见问题及解决方案 #### 1. 环境初始化失败(source命令) - **现象**:`envsetup.sh not found` - **原因**:路径错误或源码不完整 - **解决**: ```bash # 确认目录结构 ls build/envsetup.sh # 重新同步源码 repo sync -c -j4 ``` #### 2. lunch选择失败 - **现象**:`Invalid lunch combo` - **原因**:目标配置名称错误或未定义 - **解决**: ```bash # 查看可用配置列表 printconfig # 检查vendorsetup.sh是否注册 grep ums9230_6h10 vendor/*/vendorsetup.sh ``` #### 3. 内核编译错误 - **典型错误**: ```log Kernel configuration invalid: .config not found ``` - **解决步骤**: 1. 检查内核配置 ```bash cd kernel/sprd/ums9230_6h10 make ARCH=arm64 O=out ums9230_6h10_Natv_k515_defconfig ``` 2. 修复依赖缺失 ```bash sudo apt install flex bison libssl-dev ``` 3. 减少并行线程(内存不足时) ```bash make kernelcomponent -j1 # 单线程编译 ``` #### 4. 权限问题 - **现象**:`Permission denied` - **解决**: ```bash # 检查文件权限 ls -ld /home/zhujianhua/work # 递归修复所有权 sudo chown -R zhujianhua:zhujianhua AndroidU/ ``` #### 5. 编译终止(-j3问题) - **现象**:随机编译中止 - **原因**:并行任务过多导致资源竞争 - **优化方案**: ```bash # 根据CPU核心数调整-j参数 JOBS=$(($(nproc)/2)) make kernelcomponent -j$JOBS ``` ### 调试建议 1. **分步执行**: ```bash cd /home/zhujianhua/work/AndroidU/sprd_vnd/bsp source build/envsetup.sh lunch ums9230_6h10_Natv_k515-userdebug-androidt make kernelcomponent -j3 ``` 2. **日志记录**: ```bash make kernelcomponent -j3 2>&1 | tee build.log ``` 3. **环境验证**: ```bash # 检查关键变量 echo $TARGET_PRODUCT $TARGET_BUILD_VARIANT # 验证内核配置 make -C kernel/sprd/ums9230_6h10/ listconfigs ``` ### 关键文档参考 - 展锐编译手册:`bsp/vendor/sprd/docs/Kernel_Build_Guide.pdf` - Android官方编译指南:[Android Build System](https://source.android.com/docs/setup/build)[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值