ANDROID L日志系统——JAVAAPI与LIBLOG
java.lang.Object
↳ android.util.Log
API for sending log output.
Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e() methods.
public static int v(String tag, String msg) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
...>
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
//先判断ID是否是一个合法LOG_ID_MAX,这个变量定义在system/下面的Log.h里面
- if (bufID < 0 || bufID >= LOG_ID_MAX) {
jniThrowNullPointerException(env, "bad bufID");
return -1;
}
- //取出来TAG
if (tagObj != NULL)
tag = env->GetStringUTFChars(tagObj, NULL);
- //取出要写入的Message
msg = env->GetStringUTFChars(msgObj, NULL);
//调用__android_log_buf_write来写入到buffer
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
if (tag != NULL)
env->ReleaseStringUTFChars(tagObj, tag);
env->ReleaseStringUTFChars(msgObj, msg);
return res;
}
下一节就来讨论logd的实现。
1,在系统启动到init处理的时候,会解析init.rc启动logd service如下:
service logd /system/bin/logd
class core
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
socket logdw dgram 0222 logd logd
group root system
for (si = svc->sockets; si; si = si->next) {
//读取socket类型,stream或者dgram
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
//创建socket
int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid, si->socketcon ?: scon);
if (s >= 0) {
//发布socket,把创建的socketFd写到环境变量,让其它Sokect的Server端通过android_get_control_socket(mSocketName)来获得socketFd.
publish_socket(si->name, s);
}
}
int create_socket(const char *name, int type, mode_t perm, uid_t uid,
gid_t gid, const char *socketcon)
{
struct sockaddr_un addr;
int fd, ret;
char *filecon;
//调用系统调用socket来创建一个PF_UNIX的socket
fd = socket(PF_UNIX, type, 0);
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
name);
//把这个socket绑定到addr上,这个addr就与/dev/socket/*有关了
ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
// LogListener listens on /dev/socket/logdw for client
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
LogListener *swl = new LogListener(logBuf, reader);
// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
if (swl->startListener(300)) {
exit(1);
}
LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
//同时会构造一个父类SocketListener,getLogSocket()是通过logdw这个名字返回一个SocketFd
SocketListener(getLogSocket(), false),
- //把两个结构体传过来
logbuf(buf),
reader(reader) {
}
SocketListener::SocketListener(int socketFd, bool listen) {
init(NULL, socketFd, listen, false);
}
=》
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
mListen = listen;
mSocketName = socketName;
mSock = socketFd;
mUseCmdNum = useCmdNum;
pthread_mutex_init(&mClientsLock, NULL);
mClients = new SocketClientCollection();
}
int SocketListener::startListener(int backlog) {
if (!mSocketName && mSock == -1) {
- ...
- //在构造中mSocketName已经传过来了
} else if (mSocketName) {
//获得SocketFd
if ((mSock = android_get_control_socket(mSocketName)) < 0) {
- ...
}
SLOGV("got mSock = %d for %s", mSock, mSocketName);
fcntl(mSock, F_SETFD, FD_CLOEXEC);
}
//调用listen的系统调用,监听SocketFd。此时mListen为NULL,应该不会调用listen??TODO,有编译器有关??
if (mListen && listen(mSock, backlog) < 0) {
- ...
} else if (!mListen)
//创建SocketClient,并放到mClients的,mClients是存储所有SocketClient的List容器。
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
- ...
//创建PID为mThread的线程,线程执行函数是thradStart,并启动 。
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
me->runListener();
pthread_exit(NULL);
return NULL;
}
void SocketListener::runListener() {
...
rc = select(max + 1, &read_fds, NULL, NULL, NULL);
...
c = accept(mSock, &addr, &alen);
...
/* Process the pending list, since it is owned by the thread,* there is no need to lock it */while (!pendingList.empty()) {/* Pop the first item from the list */it = pendingList.begin();SocketClient* c = *it;pendingList.erase(it);/* Process it, if false is returned, remove from list */if (!onDataAvailable(c)) {//这个数据处理函数,由继承SocketListener的类来实现,在这里就是指LogListener.cpprelease(c, false);}c->decRef();}
char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
+ LOGGER_ENTRY_MAX_PAYLOAD];- //定义iov用于接收Client的writerv的内容。即一条LOG会在在buffer中
struct iovec iov = { buffer, sizeof(buffer) };
memset(buffer, 0, sizeof(buffer));
//存放Client的进程信息
char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
NULL,
0,
&iov,//真正存放LOG message
1,
control,
sizeof(control),
0,
};
int socket = cli->getSocket();
- //通过系统调用 把Client传过来的socket数据存放在hdr这个结构体中。
ssize_t n = recvmsg(socket, &hdr, 0);
struct msghdr {
void *msg_name; /* optional address */
socklen_t msg_namelen; /* size of address */
struct iovec *msg_iov; /* scatter/gather array */
size_t msg_iovlen; /* # elements in msg_iov */
void *msg_control; /* ancillary data, see below */
size_t msg_controllen; /* ancillary data buffer len */
int msg_flags; /* flags on received message */
};
struct cmsghdr {
socklen_t cmsg_len; /* data byte count, including header */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
/* followed by unsigned char cmsg_data[]; */
};
struct ucred {
pid_t pid; /* process ID of the sending process */
uid_t uid; /* user ID of the sending process */
gid_t gid; /* group ID of the sending process */
};
struct ucred *cred = NULL;
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
while (cmsg != NULL) {
if (cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SCM_CREDENTIALS) {
cred = (struct ucred *)CMSG_DATA(cmsg);
break;
}
cmsg = CMSG_NXTHDR(&hdr, cmsg);
}
if (cred == NULL) {
return false;
}
- //检查进程的权限
if (cred->uid == AID_LOGD) {
// ignore log messages we send to ourself.
// Such log messages are often generated by libraries we depend on
// which use standard Android logging.
return false;
}
android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) {
return false;
}
char *msg = ((char *)buffer) + sizeof(android_log_header_t);
n -= sizeof(android_log_header_t);
// NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
// truncated message to the logs.
if (logbuf->log((log_id_t)header->id, header->realtime,
cred->uid, cred->pid, header->tid, msg,
((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) {
reader->notifyNewLog();
}
return true;
ANDROID L日志系统——JAVAAPI与LIBLOG相关推荐
- Android L日志系统1——logd
在介绍完Android M之前的日志系统的实现之后,我们现在来看看现在最新的Android L的日志机制.Android L与之前版本最大的变化,就是日志保存的位置由Kernel的Ringer Buf ...
- Android动态日志系统Holmes
背景 美团点评公司是全球领先的一站式生活服务平台,为6亿多消费者和超过450万优质商户提供连接线上线下的电子商务网络.美团点评的业务覆盖了超过200个丰富品类和2800个城区县网络,在餐饮.外卖.酒店 ...
- 以Android L读取系统所有logcat并写入文件为例分析Android 以添加系统进程的方式申请selinux的权限执行shell脚本,以及avc:dined应该怎么申请权限
添加selinux较好的文章,可以通过adb shell dmesg > kenel.log 获取kmesg 可以看到 avc:dined 相关内容 首先说说环境: 基于Android L的ao ...
- Android Log日志系统
目录 0. 前言 1. Native的Log写过程解析 2. Socket的另一端Logd 0. 前言 Android中 logd 详解_私房菜的博客-CSDN博客_logd 里面讲了Java层Log ...
- Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化-[Android取经之路]
摘要:本节主要来讲解Android10.0 日志系统的架构分析,以及logd.logcat的初始化操作 阅读本文大约需要花费15分钟. 文章首发微信公众号:IngresGe 专注于Android系统级 ...
- Android日志系统Logcat源代码简要分析
在前面两篇文章Android日志系统驱动程序Logger源代码分析和Android应用程序框架层和系统运行库层日志系统源代码中,介绍了Android内核空间层.系统运行库层和应用程序框架层日志系统相关 ...
- Android源码解析之日志系统Logcat
转载自:http://blog.csdn.net/Luoshengyang/article/details/6606957 在前面两篇文章Android日志系统驱动程序Logger源代码分析和Andr ...
- android界面赏析,Android L的UI赏析 部分比苹果iOS 8更赏心悦目
[摘要]Material Design拥有各种交互及视觉上的变化,比苹果的iOS 8更加赏心悦目. 腾讯数码讯(编译:Lotus) 如果你是一个狂热的Android粉丝,那么在未来几个月中一定会发现很 ...
- android core log,Android 日志系统(Logcat)的实现分析
这篇说一下Android 日志系统的实现: 1. Android中的打印分为4个缓冲区和6个打印等级,在frameworks\base\core\java\android\util\Log.java中 ...
最新文章
- 修改及查看mysql数据库的字符集
- SVA Function Coverage
- List类集接口-ArrayList
- Python 的and 运算
- ssh 与 locale
- DirectX_11_游戏编程入门_1
- NB-IoT的DRX、eDRX、PSM三个模式怎么用?
- android返回键返回指定目录,Android 返回键返回到指定的Activity
- plt,cv2图片像素值的立体显示
- centos 雷凌凌ralink无线网卡驱动 安装
- 习题8.16 (简单方法)输入一个字符串,内有数字和非数字字符
- Neon Love(霓虹爱)
- 大厂团队协作工具推荐
- 基于Java和Netty实现的联机版坦克大战游戏
- C++中的FILL和MEMSET(zzl)
- VS code 设置多行注释快捷键
- DeFi:过去、现在和未来
- Arduino UNO驱动MCP9808高精度数字温度传感器
- Qt串口等接口数据协议传输时的字节拼接处理
- 英语语法最终珍藏版笔记-14独立主格结构