精华内容
下载资源
问答
  • Android logcat分析

    2020-08-01 14:11:31
    关键代码分析 各个进程调用ALOGD/ALOGI…的时候,是通过驱动节点/dev/log/main…写入到驱动的循环buffer当中,这里打开了驱动节点 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) ...

    调用结构以及代码位置

    在这里插入图片描述

    关键代码分析

    各个进程调用ALOGD/ALOGI…的时候,是通过驱动节点/dev/log/main…写入到驱动的循环buffer当中,这里打开了驱动节点

    static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
    {
    #ifdef HAVE_PTHREADS
        pthread_mutex_lock(&log_init_lock);
    #endif
    
        if (write_to_log == __write_to_log_init) {
            log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
            log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
            log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
            log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
    
            write_to_log = __write_to_log_kernel;
    
            if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
                    log_fds[LOG_ID_EVENTS] < 0) {
                log_close(log_fds[LOG_ID_MAIN]);
                log_close(log_fds[LOG_ID_RADIO]);
                log_close(log_fds[LOG_ID_EVENTS]);
                log_fds[LOG_ID_MAIN] = -1;
                log_fds[LOG_ID_RADIO] = -1;
                log_fds[LOG_ID_EVENTS] = -1;
                write_to_log = __write_to_log_null;
            }
    
            if (log_fds[LOG_ID_SYSTEM] < 0) {
                log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
            }
        }
    
    #ifdef HAVE_PTHREADS
        pthread_mutex_unlock(&log_init_lock);
    #endif
    
        return write_to_log(log_id, vec, nr);
    }
    

    将应用层write下来的内存写到循环buffer当中

    static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from) {
    ...
    	memcpy(log->buffer + log->w_off, &header, len);
    	memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
    ...
    }
    
    /* logger_offset - returns index 'n' into the log via (optimized) modulus */
    static size_t logger_offset(struct logger_log *log, size_t n)
    {
    	return n & (log->size - 1);
    }
    
    展开全文
  • 1. 类图 1.1 framework层 1.2 Native层 2 时序图 2.1logd main 2 LogBuffer 2.3 LogReader 2..4 LogListener 2 .5 CommandListener 2.6 LogKlog 2.7 LogAudit.

    1. 类图

    1.1 framework层

    1.2 Native层

    2 时序图

    2.1logd main

    2 LogBuffer

    2.3 LogReader

    2..4  LogListener

    2 .5 CommandListener

    2.6 LogKlog

    2.7 LogAudit.

    展开全文
  • 会在Logcat中作相对于的输出. 所以我们也可以通过这些信息来判断是否存在内存泄露问题 一,上面消息的第一个部分产生GC的原因,一共有四种类型 GC_CONCURRENT 当你的堆内存快被用完的时候,就会触发这个GC回收 ...

    当垃圾回收机在进行垃圾回收之后.会在Logcat中作相对于的输出. 所以我们也可以通过这些信息来判断是否存在内存泄露问题

    gc说明

    一,上面消息的第一个部分产生GC的原因,一共有四种类型

    1. GC_CONCURRENT 当你的堆内存快被用完的时候,就会触发这个GC回收
    2. GC_FOR_MALLOC 堆内存已经满了,同时又要试图分配新的内存,所以系统要回收内存
    3. GC_EXTERNAL_ALLOC 在Android3.0 (Honeycomb)以前,释放通过外部内存(比如在2.3以前,产生的Bitmap对象存储在Native Memory中)时产生.Android3.0和更高版本中不再有这种类型的内存分配了.
    4. GC_EXPLICIT 调用System.gc时产生,上图中就是点击Cause GC按钮手动触发垃圾回收器产生的log信息

    freed 1413K表示GC释放了1413K的内存

    20% free 9349K/11644K 20%表示目前可分配内存占的比例 9349K表示当前活动对象所占内存 11644K表示Heap的大小

    paused 8ms + 3ms, total 71ms 则表示触发GC应用暂停的时间和GC总共消耗的时间

    有了这些log信息就可以知道GC运行几次以后有没有成功释放出一些内存. 如果分配出去的内存在持续增加.那么很明显存在内存泄露. 如下存在内存泄露的Log信息 很明显Heap中空闲内存占总Heap的比例在缩小.Heap中活动对象所占的内存在增加.

    输入图片说明

    转载于:https://my.oschina.net/tanghaoo/blog/652121

    展开全文
  • android log 和logcat 分析(一)

    千次阅读 2015-01-27 10:23:56
    在程序开发过程中,LOG是广泛使用的用来记录程序执行过程的机制,它既可以用于程序调试,也可以用于产品运营中的事件记录。在Android系统中,提供了简单、便利的LOG机制,开发人员可以方便地使用。...

         在程序开发过程中,LOG是广泛使用的用来记录程序执行过程的机制,它既可以用于程序调试,也可以用于产品运营中的事件记录。在Android系统中,提供了简单、便利的LOG机制,开发人员可以方便地使用。在这一篇文章中,我们简单介绍在Android内核空间和用户空间中LOG的使用和查看方法。

    下图简单演示log使用方法

    public class LogDemo extends Activity {
      
     private static final String ACTIVITY_TAG="LogDemo";
     private Button bt;
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            //通过findViewById找到Button资源
            bt = (Button)findViewById(R.id.bt);
            //增加事件响应
            bt.setOnClickListener(new Button.OnClickListener(){
        @Override
       public void onClick(View v) {
        Log.v(LogDemo.ACTIVITY_TAG, "This is Verbose.");
        Log.d(LogDemo.ACTIVITY_TAG, "This is Debug.");
        Log.i(LogDemo.ACTIVITY_TAG, "This is Information");
        Log.w(LogDemo.ACTIVITY_TAG, "This is Warnning.");
        Log.e(LogDemo.ACTIVITY_TAG, "This is Error.");
       }
             
            });
        }
            
    }
    log类定义在frameworks/base/core/java/android/util/Log.java文件中。

    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));
        }
    
        /**
         * Send a {@link #DEBUG} 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 d(String tag, String msg) {
            return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
        }
    
        /**
         * Send a {@link #DEBUG} 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 d(String tag, String msg, Throwable tr) {
            return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
        }
    
        /**
         * Send an {@link #INFO} 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 i(String tag, String msg) {
            return println_native(LOG_ID_MAIN, INFO, tag, msg);
        }
    
        /**
         * Send a {@link #INFO} 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 i(String tag, String msg, Throwable tr) {
            return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
        }
    
        /**
         * Send a {@link #WARN} 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 w(String tag, String msg) {
            return println_native(LOG_ID_MAIN, WARN, tag, msg);
        }
    
        /**
         * Send a {@link #WARN} 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 w(String tag, String msg, Throwable tr) {
            return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
        }
    
        /**
         * Checks to see whether or not a log for the specified tag is loggable at the specified level.
         *
         *  The default level of any tag is set to INFO. This means that any level above and including
         *  INFO will be logged. Before you make any calls to a logging method you should check to see
         *  if your tag should be logged. You can change the default level by setting a system property:
         *      'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>'
         *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
         *  turn off all logging for your tag. You can also create a local.prop file that with the
         *  following in it:
         *      'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
         *  and place that in /data/local.prop.
         *
         * @param tag The tag to check.
         * @param level The level to check.
         * @return Whether or not that this is allowed to be logged.
         * @throws IllegalArgumentException is thrown if the tag.length() > 23.
         */
        public static native boolean isLoggable(String tag, int level);
    
        /*
         * Send a {@link #WARN} 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 tr An exception to log
         */
        public static int w(String tag, Throwable tr) {
            return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
        }
    
        /**
         * Send an {@link #ERROR} 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 e(String tag, String msg) {
            return println_native(LOG_ID_MAIN, ERROR, tag, msg);
        }
    

    e  d w 和 i 函数又调用
    println_native(LOG_ID_MAIN, ERROR, tag, msg)
    发现此定义也在Log.java中

    public static native int println_native(int bufID,
                int priority, String tag, String msg);
    }

    明显这个函数是 本地函数!!调用本地库。这也说明了log实现是在linux 层实现的,这个函数调用jni函数 在frameworks/base/core/jni/android_util_Log.cpp文件中的android_util_Log_println_native函数

    namespace android {
    
    struct levels_t {
        jint verbose;
        jint debug;
        jint info;
        jint warn;
        jint error;
        jint assert;
    };
    static levels_t levels;
    
    static int toLevel(const char* value)
    {
        switch (value[0]) {
            case 'V': return levels.verbose;
            case 'D': return levels.debug;
            case 'I': return levels.info;
            case 'W': return levels.warn;
            case 'E': return levels.error;
            case 'A': return levels.assert;
            case 'S': return -1; // SUPPRESS
        }
        return levels.info;
    }
    
    static jboolean isLoggable(const char* tag, jint level) {
        String8 key;
        key.append(LOG_NAMESPACE);
        key.append(tag);
    
        char buf[PROPERTY_VALUE_MAX];
        if (property_get(key.string(), buf, "") <= 0) {
            buf[0] = '\0';
        }
    
        int logLevel = toLevel(buf);
        return logLevel >= 0 && level >= logLevel;
    }
    
    static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
    {
        if (tag == NULL) {
            return false;
        }
    
        const char* chars = env->GetStringUTFChars(tag, NULL);
        if (!chars) {
            return false;
        }
    
        jboolean result = false;
        if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {
            char buf2[200];
            snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n",
                    chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));
    
            jniThrowException(env, "java/lang/IllegalArgumentException", buf2);
        } else {
            result = isLoggable(chars, level);
        }
    
        env->ReleaseStringUTFChars(tag, chars);
        return result;
    }
    
    bool android_util_Log_isVerboseLogEnabled(const char* tag) {
        return isLoggable(tag, levels.verbose);
    }
    
    /*
     * In class android.util.Log:
     *  public static native int println_native(int buffer, int priority, String tag, String msg)
     */
    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;
    }
    
    /*
     * JNI registration.
     */
    static JNINativeMethod gMethods[] = {
        /* name, signature, funcPtr */
        { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
        { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
    };
    
    int register_android_util_Log(JNIEnv* env)
    {
        jclass clazz = env->FindClass("android/util/Log");
    
        if (clazz == NULL) {
            ALOGE("Can't find android/util/Log");
            return -1;
        }
    
        levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I"));
        levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I"));
        levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I"));
        levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I"));
        levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I"));
        levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I"));
    
        return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));
    }
    
    }; // namespace android
    

    其中
     { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
    };
    就是我们java调用C++的本地函数,每当上层使用log.d或者log.e等所有的函数时候我们发现先调用println_native,最后调用到C++中的android_util_Log_println_native函数。

    android_util_Log_println_native内容是:

    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;
    }
    

    是个本地static函数。在内存中只存在一份,首先判断传递msg是否为空,然后判断bufid是否超过大于等于5,通过
    env->GetStringUTFChars

    获得上层传递过来的tag,

     msg = env->GetStringUTFChars(msgObj, NULL);

    获得上层传递的msg。

    __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
    调用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];
    
    printf("------\n");
    
        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;
                // 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;
        }
    
        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);
    }
    

    在这里用结构体数组iovec存贮我们log的tag,msg和prio信息,

    struct iovec {
        const void*  iov_base;
        size_t       iov_len;
    };
    通过强制转换将prio,tag和msg保存在ivo_base中,然后调用函数

    write_to_log(bufID, vec, 3);}
    我们发现这个函数是一个指针,通过指针复制最后调用的函数是
    __write_to_log_init

    int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) __attribute__((visibility ("hidden"))) = __write_to_log_init;
    static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
    {
    #ifdef HAVE_PTHREADS
        pthread_mutex_lock(&log_init_lock);
    #endif
    
        if (write_to_log == __write_to_log_init) {
            log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
            log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
            log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
            log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
    
            write_to_log = __write_to_log_kernel;
    
            if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
                    log_fds[LOG_ID_EVENTS] < 0) {
                log_close(log_fds[LOG_ID_MAIN]);
                log_close(log_fds[LOG_ID_RADIO]);
                log_close(log_fds[LOG_ID_EVENTS]);
                log_fds[LOG_ID_MAIN] = -1;
                log_fds[LOG_ID_RADIO] = -1;
                log_fds[LOG_ID_EVENTS] = -1;
                write_to_log = __write_to_log_null;
            }
    
            if (log_fds[LOG_ID_SYSTEM] < 0) {
                log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
            }
        }
    
    #ifdef HAVE_PTHREADS
        pthread_mutex_unlock(&log_init_lock);
    #endif
    
        return write_to_log(log_id, vec, nr);
    }
    

    在这个函数中首先使用线程锁函数

     pthread_mutex_lock(&log_init_lock);

    开始我们已经定义赋值了write_to_log == __write_to_log_init,所以下面的语句一定执行,

    static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };是一个static int数组,

    log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
            log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
            log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
            log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);

    每个 log_fds数组元素保存的是log_open打开的文件句柄,通过查找发现log_open函数定义在

    #if FAKE_LOG_DEVICE
    // This will be defined when building for the host.
    #define log_open(pathname, flags) fakeLogOpen(pathname, flags)
    #define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
    #define log_close(filedes) fakeLogClose(filedes)
    #else
    #define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)
    #define log_writev(filedes, vector, count) writev(filedes, vector, count)
    #define log_close(filedes) close(filedes)
    #endif

    到底使用的是上面的函数还是下面的函数,只有FAKE_LOG_DEVICE有没有定义才知道,

    打开文件system/core/liblog/Android.mk文件,发现FAKE_LOG_DEVICE在这里有定义,

    # Shared and static library for host
    # ========================================================
    LOCAL_MODULE := liblog
    LOCAL_SRC_FILES := $(liblog_host_sources)
    LOCAL_LDLIBS := -lpthread
    LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
    LOCAL_WHOLE_STATIC_LIBRARIES := libxlog
    include $(BUILD_HOST_STATIC_LIBRARY)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := liblog
    LOCAL_WHOLE_STATIC_LIBRARIES := liblog
    include $(BUILD_HOST_SHARED_LIBRARY)

    在这里的意思是,若adb为host端则定义FAKE_LOG_DEVICE为1,编译的时候就选择上面的函数编译,

    因为在android产品中大部分是作为客户端(target)使用

    # Shared and static library for target
    # ========================================================
    include $(CLEAR_VARS)
    LOCAL_MODULE := liblog
    LOCAL_SRC_FILES := $(liblog_sources)
    LOCAL_WHOLE_STATIC_LIBRARIES := libxlog
    include $(BUILD_STATIC_LIBRARY)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := liblog
    LOCAL_WHOLE_STATIC_LIBRARIES := liblog
    include $(BUILD_SHARED_LIBRARY)

    因为没有FAKE_LOG_DEVICE定义就是用下面函数

    log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)

    就是普通的linux系统的普通文件操作函数 open(pathname, (flags) | O_CLOEXEC)

    因为linux把设备当做文件看待,所以使用文件函数open打开,通过adb shell  ls /dev/log/

    我们知道在Logger驱动程序模块中,有四个设备文件节点。分别对应的是dev/log/main,dev/log/radio,dev/log/system和

    dev/log/event,这也是我们log_open 打开的四个文件,打开方式可读可写。

    顺便把下面两个也列出来

     log_writev(filedes, vector, count) writev(filedes, vector, count)

    log_close(filedes) close(filedes)

    执行完文件打开操作后,又将write_to_log 指针赋值= __write_to_log_kernel,这个函数才是真正的往log驱动模块里面写日志,

    static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
    {
        ssize_t ret;
        int log_fd;
    
        if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
            log_fd = log_fds[(int)log_id];
        } else {
            return EBADF;
        }
    
        do {
            ret = log_writev(log_fd, vec, nr);
        } while (ret < 0 && errno == EINTR);
    
        return ret;
    }
    

    显示判断log_id值是否大于等于0小于4

    typedef enum {
        LOG_ID_MAIN = 0,
        LOG_ID_RADIO = 1,
        LOG_ID_EVENTS = 2,
        LOG_ID_SYSTEM = 3,
    
        LOG_ID_MAX
    } log_id_t;
    


    然后执行写操作函数ret = log_writev(log_fd, vec, nr);

    上面分析给出了
    log_writev(filedes, vector, count) writev(filedes, vector, count)

     所以使用函数是writev(filedes, vector, count)

    int  writev( int  fd, const struct iovec*  vecs, int  count )
    {
        int   total = 0;
    
        for ( ; count > 0; count--, vecs++ ) {
            const char*  buf = (const char*)vecs->iov_base;
            int          len = (int)vecs->iov_len;
            
            while (len > 0) {
                int  ret = write( fd, buf, len );
                if (ret < 0) {
                    if (total == 0)
                        total = -1;
                    goto Exit;
                }
                if (ret == 0)
                    goto Exit;
    
                total += ret;
                buf   += ret;
                len   -= ret;
            }
        }
    Exit:    
        return total;
    }

    这里就是简单的文件操作函数write,这里就不分析了。











    展开全文
  • logcat源码分析

    2014-01-07 13:17:36
     Logcat工具内置在Android系统中,可以在主机上通过adb logcat命令来查看模拟机上日志信息。主要是介绍Logcat读取日志的主线,即从打开日志设备文件到读取日志设备文件的日志记录到输出日志记录的主要过程.  ...
  • logcat日志分析

    2020-05-22 16:54:02
    1、Android日志系统提供了记录和查看系统调试信息的功能,日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过logcat命令来查看和使用。 2、logca 日志开头: 1....... beginning of xxx 3...
  • App logcat日志分析

    2020-02-23 22:00:06
    文章目录logcat日志文件缓冲区 logcat日志文件 android日志系统提供了记录和查看系统调试信息的功能,日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过logcat命令来查看和使用,命令为: adb ...
  • adb logcat日志分析

    千次阅读 2014-07-30 11:30:59
    1、adb logcat 1)此命令用于输出手机或模块器开机以及用户对手机/模拟器进行操作后生成的系统日志,最后显示的日志为用户最近操作记录的日志。 2)logcat输出的日志类似为 [img]file:///F:/androidTest/adb%...
  • Android系统logcat实现分析

    千次阅读 2015-11-05 15:24:02
    一、logcat可执行程序 system/core/logcat/
  • Logcat源码分析(一)

    2014-11-06 14:51:11
    http://blog.csdn.net/hudashi/article/details/7073155 ... ...Logcat工具内置在Android系统中,可以在主机上通过adb logcat命令来查看模拟机上日志信息。如果你还不知道Logcat的使用,请参看《logc
  • LogCat

    2015-12-03 15:33:09
    日志在任何项目的开发过程中都会起到非常重要的作用,在Android项目中如果你想要查看日志则必须要使用LogCat工具。当你第一次在Eclipse中运行Android项目的时候,Eclipse会提醒你一次是否要添加LogCat这个工具
  • Logcat

    2020-04-08 10:46:07
    Logcat 是 Android SDK 里面提供的命令行下的 Logging 工具,用法简单,使用方便,相关的介绍可以参考 Android Developer 链接: http://developer.android.com/tools/help/logcat.html 用法 命令格式如下,在<...
  • logcat

    2018-12-10 17:03:07
    logcat 2017年09月04日 19:31:52 Poirot_ 阅读数:1014更多 个人分类: Eclipse Time 时间 PID process id也就是进程id TID 线程id application 程序 Tag 标识  text 描述       1、Time ...
  • Android logcat解析与问题分析

    千次阅读 2018-07-22 12:35:32
    logcat是Android中一个命令行工具,可以用于得到程序的log信息。 一、logcat 结构  1、  这个结构在AS或者exlipse上面看的更清楚 二、logcat中地址反差backtrace  当程序崩溃的时候会在loacat中打印出...
  • app日志文件分析logcat

    千次阅读 2019-05-27 14:02:17
    文件带时间:adb logcat -v time > E:\lianxiadb\logcat_time.txt 崩溃闪退生成文件:cd /data/system/dropbox
  • Logcat源码分析(五)

    千次阅读 2011-12-15 10:48:04
     从前面的分析中看出,最终日志设备文件内容的输出是通过logcat.cpp文件的printNextEntry函数进行的: static void printNextEntry(log_device_t* dev) {  maybePrintStart(dev);  if (g_printBinary) {
  • Android日志系统Logcat源代码简要分析.pdf
  • Logcat源码分析(四)

    千次阅读 2011-12-15 10:47:15
    继续看logcat.cpp的readLogLines()这个函数 if (result == 0) {  // we did our short timeout trick and there's nothing new  // print everything we have and wait for more data  sleep = true;
  • Logcat源码分析(二)

    千次阅读 2011-12-15 10:45:59
    继续往下看logcat.cpp的main函数,它调用setupOutput()函数来初始化输出文件: Android::setupOutput();  setupOutput()函数定义如下: static void setupOutput() {    if (g_outputFileName ...
  • Logcat源码分析(三)

    千次阅读 2011-12-15 10:46:41
    读取日志设备文件内容的readLogLines()函数也在logcat.cpp中,只是它是定义在Android命名空间中。所以要以Android::readLogLines(devices)方式调用。 static void readLogLines(log_device_t* devices) {  ...
  • logcat源码分析(六)

    千次阅读 2011-12-15 10:48:44
    继续看logcat.cpp的processBuffer函数,如果执行完Android_log_shouldPrintLine函数后,表明当前日志记录应当输出,则调用android_log_printLogLine函数来输出日志记录到文件fd中, 这个函数也是定义在system/core...
  • Android日志系统Logcat源代码简要分析

    万次阅读 多人点赞 2011-07-15 02:27:42
    在前面两篇文章Android日志系统驱动程序Logger源代码分析和Android应用程序框架层和系统运行库层日志系统源代码中,介绍了Android内核空间层、系统运行库层和应用程序框架层日志系统相关的源代码,其中,后一篇文章...
  • fiddler抓包 打开apk 得到包 GET /app/services?OPT=161&_t=2019-09-20+14%3A50%3A28&body=&_s=b927f042a361e6e04e4f1dbc25945fa9 HTTP/1.1 我们分析 _s=b927f042a361e6e04e4f1dbc...
  • Android读取logcat信息

    2019-10-03 19:51:16
    测试的时候,经常遇到开发需要logcat分析定位bug,今天简单记录一下获取logcat的方法 前提条件:电脑中要安装好Android SDK 1.cmd 进入到这个界面 2.电脑连上手机,手机记得打开开发者选项,usb调试。 3.输入...
  • Logcat——更优雅的日志分析

    千次阅读 2017-06-25 15:53:25
    嵌入式开发 Logcat 的过滤及输出到外部存储设备的思路。 手机开发可以单独运行的Logcat工具类

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,209
精华内容 6,483
关键字:

logcat分析