赞
踩
第一篇博客,讲的主要是c++,java中打印log,然后通过socket传给logd,然后logd是如何处理接受log的。
logcat -c
清除已有log信息
logcat -b main 显示主缓冲区的log
logcat -b radio 显示无线缓冲区的log
logcat -b events 显示事件缓冲区的log
logcat -f [filename] 将log保存到指定的文件中,例如logcat -b radio -f /data/radio.log
比较常用的是显示时间:logcat -v time &
logcat -g 查看缓冲区的大小
logcat -g main
logcat -g radio
logcat -g events
logcat打印/dev/log设备下的三个文件radio, events, main数据
logcat默认是输出main、system缓冲区的log
在android的java层的log有几种,比如Log Slog Rlog
我们先来看看其实现:
Slog
- public final class Slog {
-
- private Slog() {
- }
-
- public static int v(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag, msg);
- }
-
- public static int v(String tag, String msg, Throwable tr) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.VERBOSE, tag,
- msg + '\n' + Log.getStackTraceString(tr));
- }
-
- public static int d(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_SYSTEM, Log.DEBUG, tag, msg);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Rlog
- public final class Rlog {
-
- private Rlog() {
- }
-
- public static int v(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.VERBOSE, tag, msg);
- }
-
- public static int v(String tag, String msg, Throwable tr) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.VERBOSE, tag,
- msg + '\n' + Log.getStackTraceString(tr));
- }
-
- public static int d(String tag, String msg) {
- return Log.println_native(Log.LOG_ID_RADIO, Log.DEBUG, tag, msg);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Log
- private Log() {
- }
-
- /**
- * Send a {@link #VERBOSE} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param msg The message you would like logged.
- */
- public static int v(String tag, String msg) {
- return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
- }
-
- /**
- * Send a {@link #VERBOSE} log message and log the exception.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param msg The message you would like logged.
- * @param tr An exception to log
- */
- public static int v(String tag, String msg, Throwable tr) {
- return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
最终都是调用了printIn_native只是id不同main,system,radio。
- static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
- jint bufID, jint priority, jstring tagObj, jstring msgObj)
- {
- const char* tag = NULL;
- const char* msg = NULL;
-
- if (msgObj == NULL) {
- jniThrowNullPointerException(env, "println needs a message");
- return -1;
- }
-
- if (bufID < 0 || bufID >= LOG_ID_MAX) {
- jniThrowNullPointerException(env, "bad bufID");
- return -1;
- }
-
- if (tagObj != NULL)
- tag = env->GetStringUTFChars(tagObj, NULL);
- msg = env->GetStringUTFChars(msgObj, NULL);
-
- 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;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
然后又调用了__android_log_buf_write函数,是在system/core/liblog/logd_write.c文件中
- int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
- {
- struct iovec vec[3];
- char tmp_tag[32];
-
- if (!tag)
- tag = "";
-
- /* XXX: This needs to go! */
- if ((bufID != LOG_ID_RADIO) &&
- (!strcmp(tag, "HTC_RIL") ||
- !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
- !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
- !strcmp(tag, "AT") ||
- !strcmp(tag, "GSM") ||
- !strcmp(tag, "STK") ||
- !strcmp(tag, "CDMA") ||
- !strcmp(tag, "PHONE") ||
- !strcmp(tag, "SMS"))) {
- bufID = LOG_ID_RADIO;//这些tag也归类到radio中
- /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
- snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
- tag = tmp_tag;
- }
-
- #if __BIONIC__
- if (prio == ANDROID_LOG_FATAL) {
- android_set_abort_message(msg);
- }
- #endif
-
- vec[0].iov_base = (unsigned char *) &prio;
- vec[0].iov_len = 1;
- vec[1].iov_base = (void *) tag;
- vec[1].iov_len = strlen(tag) + 1;
- vec[2].iov_base = (void *) msg;
- vec[2].iov_len = strlen(msg) + 1;
-
- return write_to_log(bufID, vec, 3);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
而write_to_log就是__write_to_log_init函数
- static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
- static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
因为这里log库是公用的代码,host target都是也就是有的是pc代码,有的是手机代码共有了
- static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
- {
- #if !defined(_WIN32)
- pthread_mutex_lock(&log_init_lock);
- #endif
-
- if (write_to_log == __write_to_log_init) {
- int ret;
-
- ret = __write_to_log_initialize();//先调用了__write_to_log_initialize
- if (ret < 0) {
- #if !defined(_WIN32)
- pthread_mutex_unlock(&log_init_lock);
- #endif
- #if (FAKE_LOG_DEVICE == 0)
- if (pstore_fd >= 0) {
- __write_to_log_daemon(log_id, vec, nr);//然后调用__write_to_log_daemon方法
- }
- #endif
- return ret;
- }
-
- write_to_log = __write_to_log_daemon;
- }
-
- #if !defined(_WIN32)
- pthread_mutex_unlock(&log_init_lock);
- #endif
-
- return write_to_log(log_id, vec, nr);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
上面的函数我们先调用了__write_to_log_initialize函数,然后再调用了__write_to_log_daemon函数
- static int __write_to_log_initialize()
- {
- int i, ret = 0;
-
- #if FAKE_LOG_DEVICE//这个是host才有的
- for (i = 0; i < LOG_ID_MAX; i++) {
- char buf[sizeof("/dev/log_system")];
- snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
- log_fds[i] = fakeLogOpen(buf, O_WRONLY);
- }
- #else
- if (pstore_fd < 0) {
- pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
- }
-
- if (logd_fd < 0) {
- i = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
- if (i < 0) {
- ret = -errno;
- } else if (TEMP_FAILURE_RETRY(fcntl(i, F_SETFL, O_NONBLOCK)) < 0) {
- ret = -errno;
- close(i);
- } else {
- struct sockaddr_un un;
- memset(&un, 0, sizeof(struct sockaddr_un));
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/logdw");// 我们的socket
-
- if (TEMP_FAILURE_RETRY(connect(i, (struct sockaddr *)&un,
- sizeof(struct sockaddr_un))) < 0) {
- ret = -errno;
- close(i);
- } else {
- logd_fd = i;//连接socket成功后,保存在log_fd这个全局变量中
- }
- }
- }
- #endif
-
- return ret;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
上面初始化,我们的socket是dev/socket/logdw,__write_to_log_daemon函数我们就不看了就是往socket写log,而用的就是log_fd这个fd。
往socket写之后,又会在哪里接受呢?
答案是logd
我们先看下logd的main函数
在logd的main函数中如下代码:
- 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(), false),
- logbuf(buf),
- reader(reader) {
- }
- int LogListener::getLogSocket() {
- static const char socketName[] = "logdw";
- int sock = android_get_control_socket(socketName);
-
- if (sock < 0) {
- sock = socket_local_server(socketName,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_DGRAM);
- }
-
- int on = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- return -1;
- }
- return sock;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
监听的socket为logdw,当有socket数据来的会调用onDataAvailable函数,这个函数我们就不看了,在这个函数中调用了LogBuffer::log函数。
- int LogBuffer::log(log_id_t log_id, log_time realtime,
- uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len) {
- if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
- return -EINVAL;
- }
-
- LogBufferElement *elem = new LogBufferElement(log_id, realtime,//新建一个LogBufferElement对象
- uid, pid, tid, msg, len);
- int prio = ANDROID_LOG_INFO;
- const char *tag = NULL;
- if (log_id == LOG_ID_EVENTS) {
- tag = android::tagToName(elem->getTag());
- } else {
- prio = *msg;
- tag = msg + 1;
- }
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- // Log traffic received to total
- pthread_mutex_lock(&mLogElementsLock);
- stats.add(elem);//统计信息
- stats.subtract(elem);
- pthread_mutex_unlock(&mLogElementsLock);
- delete elem;
- return -EACCES;
- }
-
- pthread_mutex_lock(&mLogElementsLock);
-
- // Insert elements in time sorted order if possible
- // NB: if end is region locked, place element at end of list
- LogBufferElementCollection::iterator it = mLogElements.end();
- LogBufferElementCollection::iterator last = it;
- while (last != mLogElements.begin()) {
- --it;
- if ((*it)->getRealTime() <= realtime) {
- break;
- }
- last = it;
- }
-
- if (last == mLogElements.end()) {
- mLogElements.push_back(elem);
- } else {
- uint64_t end = 1;
- bool end_set = false;
- bool end_always = false;
-
- LogTimeEntry::lock();
-
- LastLogTimes::iterator t = mTimes.begin();
- while(t != mTimes.end()) {
- LogTimeEntry *entry = (*t);
- if (entry->owned_Locked()) {
- if (!entry->mNonBlock) {
- end_always = true;
- break;
- }
- if (!end_set || (end <= entry->mEnd)) {
- end = entry->mEnd;
- end_set = true;
- }
- }
- t++;
- }
-
- if (end_always
- || (end_set && (end >= (*last)->getSequence()))) {
- mLogElements.push_back(elem);//将对象插入mLogElements
- } else {
- mLogElements.insert(last,elem);
- }
-
- LogTimeEntry::unlock();
- }
-
- stats.add(elem);
- maybePrune(log_id);
- pthread_mutex_unlock(&mLogElementsLock);
-
- return len;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
这个函数主要讲log的内容信息封装在LogBufferElement,然后放到mLogElements中,最后调用maybePrune函数。
- // Prune at most 10% of the log entries or 256, whichever is less.
- //
- // mLogElementsLock must be held when this function is called.
- void LogBuffer::maybePrune(log_id_t id) {
- size_t sizes = stats.sizes(id);//某个id的log个数
- unsigned long maxSize = log_buffer_size(id);
- if (sizes > maxSize) {
- size_t sizeOver = sizes - ((maxSize * 9) / 10);
- size_t elements = stats.elements(id);
- size_t minElements = elements / 10;
- unsigned long pruneRows = elements * sizeOver / sizes;
- if (pruneRows <= minElements) {
- pruneRows = minElements;
- }
- if (pruneRows > 256) {
- pruneRows = 256;
- }
- prune(id, pruneRows);
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
我们首先看下这个英文注释,如果某个id的log超过了最大值,要删除256或者log总数的10%。
我们再来看看log_buffer_size这个函数,这个函数是某个id的log最大数。
- int LogBuffer::setSize(log_id_t id, unsigned long size) {
- // Reasonable limits ...
- if (!valid_size(size)) {
- return -1;
- }
- pthread_mutex_lock(&mLogElementsLock);
- log_buffer_size(id) = size;
- pthread_mutex_unlock(&mLogElementsLock);
- return 0;
- }
在setSize函数中初始化,那我们再看看是谁调用了setSize函数
- void LogBuffer::init() {
- static const char global_tuneable[] = "persist.logd.size"; // Settings App
- static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
-
- unsigned long default_size = property_get_size(global_tuneable);//从系统属性中获取默认大小
- if (!default_size) {
- default_size = property_get_size(global_default);
- }
-
- log_id_for_each(i) {
- char key[PROP_NAME_MAX];
-
- snprintf(key, sizeof(key), "%s.%s",
- global_tuneable, android_log_id_to_name(i));
- unsigned long property_size = property_get_size(key);//从系统属性中获取某个log id的大小
-
- if (!property_size) {
- snprintf(key, sizeof(key), "%s.%s",
- global_default, android_log_id_to_name(i));
- property_size = property_get_size(key);
- }
-
- if (!property_size) {
- property_size = default_size;
- }
-
- if (!property_size) {
- property_size = LOG_BUFFER_SIZE;//没有设置属性就是这个值,是256k
- }
-
- if (setSize(i, property_size)) {
- setSize(i, LOG_BUFFER_MIN_SIZE);
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
获取系统属性的话,是下面这个函数计算出来。系统属性persist.logd.size,或者persist.logd.size.radio等
- static unsigned long property_get_size(const char *key) {
- char property[PROPERTY_VALUE_MAX];
- property_get(key, property, "");
-
- char *cp;
- unsigned long value = strtoul(property, &cp, 10);
-
- switch(*cp) {
- case 'm':
- case 'M':
- value *= 1024;
- /* FALLTHRU */
- case 'k':
- case 'K':
- value *= 1024;
- /* FALLTHRU */
- case '\0':
- break;
-
- default:
- value = 0;
- }
-
- if (!valid_size(value)) {
- value = 0;
- }
-
- return value;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
最后我们每个log id的最大值都是256k,超过的话就要调用prune删除对应id的log了。
最后我们可以通过设置系统属性persist.logd.size来设置每个log id的最大缓存值,或者persist.logd.size.radio设置每个id的最大缓存值。
步骤:
将手机连上电脑并且进入root
setproppersist.logd.size.radio 1024k
reboot 重启
另外可以用getprop | grep logd查看设置的属性是否生效
logcat -g 可以查看每个id 的缓存大小
当然这是通过属性的方法设置,我们还可以通过logcat的命令,logcat -G 10m是设置所有的id的大小,logcat -b radio -G 10m是设置radio的log的缓存大小
在logcat中有如下代码,处理设置缓存大小:
- case 'G': {
- char *cp;
- if (strtoll(optarg, &cp, 0) > 0) {
- setLogSize = strtoll(optarg, &cp, 0);
- } else {
- setLogSize = 0;
- }
-
- switch(*cp) {
- case 'g':
- case 'G':
- setLogSize *= 1024;
- /* FALLTHRU */
- case 'm':
- case 'M':
- setLogSize *= 1024;
- /* FALLTHRU */
- case 'k':
- case 'K':
- setLogSize *= 1024;
- /* FALLTHRU */
- case '\0':
- break;
-
- default:
- setLogSize = 0;
- }
-
- if (!setLogSize) {
- fprintf(stderr, "ERROR: -G <num><multiplier>\n");
- return EXIT_FAILURE;
- }
- }
- break;
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
最终会设置到logd中去,在logcat中调用的是android_logger_set_log_size函数
- if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
- logcat_panic(false, "failed to set the log size");
- }
最终会调用到到logd中的runCommand中:
- int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- setname();
- if (!clientHasLogCredentials(cli)) {
- cli->sendMsg("Permission Denied");
- return 0;
- }
-
- if (argc < 3) {
- cli->sendMsg("Missing Argument");
- return 0;
- }
-
- int id = atoi(argv[1]);
- if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
- cli->sendMsg("Range Error");
- return 0;
- }
-
- unsigned long size = atol(argv[2]);
- if (mBuf.setSize((log_id_t) id, size)) {
- cli->sendMsg("Range Error");
- return 0;
- }
-
- cli->sendMsg("success");
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
最终也会调用到LogBuffer::setSize函数,只是写属性后是永久生效的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。