Android Lib层打印log之------bionic库打印log

本文介绍在Android系统中如何通过__libc_format_log()函数替代printf(),实现log信息的有效记录。文章详细解释了如何使用该函数及其参数配置,并通过源码跟踪的方式展示了log信息最终如何被写入/dev/log/main文件中。

1. 前提:

    android系统把标准输出stdout从定向到/dev/null 中,所以logcat无法查看printf()打印的log信息。

2. 实际操作:

  1. 使用头文件: # include<private/logc_logging.h>
  2. 需要打印log使用: __libc_format_log()
  3. 例子:
# include<private/logc_logging.h>  //也可以是 #include "private/libc_logging.h"

xxx_func() {
    /** 
     * int __libc_format_log(int priority, const char* tag, const char* format, ...)
     * 
     * priority : int, 是在private/libc_logging.h定义的log的level,与java层的类似。
     *   参考"/bionic/libc/bionic/private/libc_logging.h" 定义的ANDROID_LOG_DEBUG。
     * tag :    char* , log的Tag信息。
     * format : char* , 格式化的字符串, 
     */
    char * tag = "DroidMage"; 
    char * format = "%s"; 
    char * msg = "This is for test!";
    __libc_format_log(ANDROID_LOG_DEBUG, tag, format, msg);
}

Note: Google好久都没什么好的发现,有一天浏览bionic源码,发现android底层有打印log的方法。(以android源码为根目录): /bionic/libc/private/logc_logging.cpp

3. 跟踪源码:libc_logging.cpp

int __libc_format_log(int priority, const char* tag, const char* format, ...) {
  va_list args;
  // 用来获得可变参数存入args,可变参数的标准用法。
  va_start(args, format); 
  int result = __libc_format_log_va_list(priority, tag, format, args);
  va_end(args);
  return result;
}

Note:点击参看va_start说明。

  • 继续跟踪 __libc_format_log_va_list():
int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
  char buffer[1024];
  // BufferOutputStream 是一个c++类,也在libc_logging.cpp中的。可以自行查看。
  BufferOutputStream os(buffer, sizeof(buffer)); 
  // 下面对参数的操作,将参数格式化保存在buffer中。
  out_vformat(os, format, args);
  // 关键: 返回 __libc_write_log()的调用 ,下面继续跟踪。
  return __libc_write_log(priority, tag, buffer);
}
  • 继续跟踪 __libc_write_log():
static int __libc_write_log(int priority, const char* tag, const char* msg) {
#ifdef TARGET_USES_LOGD
  ... // 由于TARGET_USES_LOGD未定义,跳过这里。
#else

  // 这里打开了/dev/log/main文件,也是logcat查看log的地方。
  // TEMP_FAILURE_RETRY不断尝试操作。操作成功返回,或则发生错误返回-1,错误类型保存'errno'
  int main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));

  // main_log_fd 等于-1表示打开文件失败
  if (main_log_fd == -1) {
   // 判断出错类型是不是文件夹不存在的错误,errno是在<errno.h>中定义, 在TEMP_FAILURE_RETRY中使用。
      if (errno == ENOTDIR) { 
      // /dev/log isn't a directory? Maybe we're running on the host? Try stderr instead.
      // __libc_write_stderr()与__libc_write_log()类似,打开/dev/stderr并写入。请自行查看源码。
      return __libc_write_stderr(tag, msg);
    }
  return -1;
  }

  iovec vec[3];
  vec[0].iov_base = &priority;
  vec[0].iov_len = 1;
  vec[1].iov_base = const_cast<char*>(tag);
  vec[1].iov_len = strlen(tag) + 1;
  vec[2].iov_base = const_cast<char*>(msg);
  vec[2].iov_len = strlen(msg) + 1;
#endif
  // 这里就把log信息写入文件了
  int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
  close(main_log_fd);
  return result;
}
  • 在 unistd.h 定义了TEMP_FAILURE_RETRY 的宏:
/* Evaluate EXPRESSION, and repeat as long as it returns -1 with 'errno'
   set to EINTR.  */
/* 这里的说明:不断尝试进行操作。 结果:操作成功。或则发生错误返回-1,并把错误类型保存'errno' */
// 具体可以参看博客:http://blog.youkuaiyun.com/zhangwu416826/article/details/17438591

# define TEMP_FAILURE_RETRY(expression) \
  (__extension__                                  \
    ({ long int __result;                             \
       do __result = (long int) (expression);                     \
       while (__result == -1L && errno == EINTR);                 \
       __result; }))
#endif

4. 后记:

最初是抱着“Google的工程师是如何调试lib层代码的呢?”的疑问浏览bionic库的。
初来乍到,欢迎拍砖。

<think>好的,我现在需要解决用户遇到的“ubuntu Sub-process gpgv returned an error code (100)”问题。首先,我要理解这个错误的背景。通常,在Ubuntu系统中使用apt-get或apt命令更新软件包时,可能会遇到这个错误。错误代码100与GPG验证有关,GPG用于验证软件包的签名,确保其来源可信。 接下来,我应该分步骤分析可能的原因。首先想到的是软件源列表中的GPG密钥过期或无效。当系统尝试下载新的软件包信息时,会使用这些密钥来验证,如果密钥有问题,就会导致验证失败,从而触发这个错误。 另一个可能的原因是网络问题,比如在下载密钥文件时连接不稳定,导致下载的密钥不完整或被破坏。此外,系统时间不正确也可能影响GPG验证,因为证书的有效期依赖于正确的时间设置。 用户可能需要检查软件源是否正确,有时第三方源的密钥可能已更新,而本地没有及时同步。此外,手动导入密钥失败或密钥服务器不可达也可能导致此问题。 接下来,我需要整理解决步骤。第一步通常是更新本地的软件包列表并尝试修复损坏的包。可以建议用户运行`sudo apt update`和`sudo apt install -f`,但用户可能已经尝试过这些基本步骤,所以需要更深入的解决方案。 如果基本步骤无效,可能需要清除缓存的软件包信息,即删除`/var/lib/apt/lists`目录下的文件,然后重新生成。这可以解决因缓存损坏引起的问题。 然后,处理GPG密钥的问题。可以指导用户定位到具体的错误源,通常在apt update的输出中会有提示哪个仓的密钥验证失败。找到对应的仓后,手动下载并导入正确的密钥。例如,使用`sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys [密钥ID]`命令。 如果手动导入密钥无效,可能需要检查系统的日期和时间是否正确,特别是如果系统时钟偏差较大,GPG验证会失败。可以使用`timedatectl`命令来检查和调整时间设置。 另外,有时特定的仓可能暂时不可用或密钥服务器有问题,可以尝试更换镜像源或暂时禁用有问题的源,再重新更新。 最后,如果所有方法都失败,可能需要更彻底地清除APT的缓存和配置,或者检查系统日志以获取更详细的错误信息,帮助进一步诊断问题。 需要确保给出的步骤清晰,用户能够逐步执行,并且解释每个步骤的原因,这样用户能理解为什么要这样做。同时,提醒用户在操作前备份重要数据,避免误操作导致系统问题。</think>遇到Ubuntu中`Sub-process gpgv returned an error code (100)`错误时,通常与软件源的GPG密钥验证失败有关。以下是逐步解决方案: --- ### 1. **更新软件源并修复包依赖** 先尝试更新软件源并修复依赖关系: ```bash sudo apt update sudo apt install -f ``` 若错误依然存在,继续下一步。 --- ### 2. **清除APT缓存** 损坏的缓存文件可能导致GPG验证失败。删除缓存并重新生成: ```bash sudo rm -rf /var/lib/apt/lists/* sudo mkdir -p /var/lib/apt/lists/partial sudo apt clean sudo apt update ``` --- ### 3. **手动修复GPG密钥** #### 步骤1:定位出错的软件源 运行`sudo apt update`时,错误信息中会显示具体是哪个源的密钥失败,例如: ``` W: GPG error: http://example.com bionic InRelease: The following signatures couldn&#39;t be verified because the public key is not available: NO_PUBKEY 123456789ABCDEF ``` 记录下`NO_PUBKEY`后的密钥ID(如`123456789ABCDEF`)。 #### 步骤2:手动导入密钥 使用以下命令从Ubuntu官方密钥服务器导入缺失的密钥: ```bash sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 123456789ABCDEF ``` 替换`123456789ABCDEF`为实际的密钥ID。 --- ### 4. **检查系统时间** GPG验证依赖系统时间。如果时间不准确,会导致验证失败: ```bash # 查看当前时间 timedatectl # 启用自动时间同步(如果未启用) sudo timedatectl set-ntp on ``` --- ### 5. **更换软件源镜像** 某些镜像源可能临时不可用。尝试更换为其他镜像: - 使用`software-properties-gtk`工具手动选择其他源: ```bash sudo software-properties-gtk ``` - 或直接编辑源文件: ```bash sudo nano /etc/apt/sources.list ``` 注释掉问题源,更换为`http://archive.ubuntu.com/ubuntu`等官方源。 --- ### 6. **彻底重置APT配置(终极方案)** 如果上述步骤无效,尝试完全重置APT配置: ```bash # 备份原有配置 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak # 恢复默认源 echo "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) main restricted universe multiverse" | sudo tee /etc/apt/sources.list echo "deb http://security.ubuntu.com/ubuntu $(lsb_release -sc)-security main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list # 更新并清理 sudo apt update sudo apt dist-upgrade ``` --- ### 总结 此错误通常由以下原因引起: 1. **密钥过期或缺失**:需手动导入。 2. **缓存损坏**:清除缓存并重建。 3. **系统时间错误**:校准时间。 4. **镜像源问题**:更换可靠源。 如果问题仍未解决,可检查系统日志获取更多细节: ```bash grep -i gpg /var/log/apt/term.log ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值