查看原文
其他

Android10系统源码的libc中添加日志输出接口

哆啦安全 2022-08-17

The following article is from 卓码空间 Author QDroid88888


一、libc中日志输出讨论

安卓源码libc中,默认提供了日志调试输出接口。源码位于如下:

//头文件定义
bionic/libc/async_safe/include/async_safe/log.h
//实现文件
bionic/libc/async_safe/async_safe_log.cpp

通过async_safe_log.cpp代码分析,写入日志主要是使用UNIX domain socket建立到域"/dev/socket/logdw"的通信,然后写入日志数据。核心逻辑代码如下:

//正在写入日志的方法,主要调用open_log_socket建立socket连接,然后写数据进去
int async_safe_write_log(int priority, const char* tag, const char* msg) {
  int main_log_fd = open_log_socket();
  if (main_log_fd == -1) {
    // Try stderr instead.
    return write_stderr(tag, msg);
  }

  iovec vec[6];
  char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN;
  vec[0].iov_base = &log_id;
  vec[0].iov_len = sizeof(log_id);
  uint16_t tid = gettid();
  vec[1].iov_base = &tid;
  vec[1].iov_len = sizeof(tid);
  timespec ts;
  clock_gettime(CLOCK_REALTIME, &ts);
  log_time realtime_ts;
  realtime_ts.tv_sec = ts.tv_sec;
  realtime_ts.tv_nsec = ts.tv_nsec;
  vec[2].iov_base = &realtime_ts;
  vec[2].iov_len = sizeof(realtime_ts);

  vec[3].iov_base = &priority;
  vec[3].iov_len = 1;
  vec[4].iov_base = const_cast<char*>(tag);
  vec[4].iov_len = strlen(tag) + 1;
  vec[5].iov_base = const_cast<char*>(msg);
  vec[5].iov_len = strlen(msg) + 1;

  int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
  __close(main_log_fd);
  return result;
}

//建立到/dev/socket/logdw的通信
static int open_log_socket() {
  // ToDo: Ideally we want this to fail if the gid of the current
  // process is AID_LOGD, but will have to wait until we have
  // registered this in private/android_filesystem_config.h. We have
  // found that all logd crashes thus far have had no problem stuffing
  // the UNIX domain socket and moving on so not critical *today*.

  int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
  if (log_fd == -1) {
    return -1;
  }

  union {
    struct sockaddr addr;
    struct sockaddr_un addrUn;
  } u;
  memset(&u, 0, sizeof(u));
  u.addrUn.sun_family = AF_UNIX;
  strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path));

  if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) {
    __close(log_fd);
    return -1;
  }

  return log_fd;
}

由于以上方法用着不是很爽,下面将通过"#define"定义几个常用的日志打印宏定义。

二、方便日志输出接口定义

参照平时ndk开发中LOGD/LOGI/LOGE的宏定义,在bionic/libc/async_safe/include/async_safe/log.h文件中定义如下方便libc中调用的日志接口。如下所示:


三、在libc中的open函数中调用




四、测试效果

编译刷机之后,终端日志输出效果还不错:


上一篇玩转安卓10源码开发定制(19)Java核心库libcore中添加Log接口任意调用

玩转Android10源码开发文章目录:

玩转Android10源码开发定制(一)源码下载编译

玩转Android10源码开发定制(二)刷机操作

玩转Android10源码开发定制(二)刷机操作之fastboot刷机演示

玩转Android10源码开发定制(二)刷机操作之Recovery刷机演示

玩转Android10源码开发定制(三)源码中编译手机刷机包

玩转Android10源码开发定制(四)源码开发环境搭建

玩转Android10源码开发定制(五)源码编译开发中常用命令

玩转Android10源码开发定制(六)修改内核源码绕过反调试检测

玩转Android10源码开发定制(七)修改ptrace绕过反调试

玩转Android10源码开发定制(八)内置Apk到系统

玩转Android10源码开发定制(九)内置frida-gadget so文件和frida-server可执行文件到系统

玩转Android10源码开发定制(十)增加获取当前运行最顶层的Activity命令

玩转Android10源码开发定制(11)内核篇之安卓内核模块开发编译

玩转Android10源码开发定制(12)内核篇之logcat输出内核日志 玩转Android10源码开发定制(13)修改安卓源码关闭selinux

玩转Android10源码开发定制(14)修改安卓源码手机永不休眠

玩转Android10源码开发定制(15)实现跳过开机向导、插电源线不休眠等默认配置

玩转Android10源码开发定制(16)LineageOS中编译user模式的系统

玩转Android10源码开发定制(17)开发并内置具有系统权限(system)的App

玩转安卓10源码开发定制(18)编译Windows平台adb和fastboot工具

玩转安卓10源码开发定制(19)Java核心库libcore中添加Log接口任意调用


欢迎各位关注公众号

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存