Interpreting the implementation of the Android LOG Mechanism: (3) Writing Device Files in JNI and c/c ++ Domains

Source: Internet
Author: User

 

Android provides a user-level lightweight LOG Mechanism. Its implementation runs through Java, JNI, local c/c ++ implementation, Linux kernel driver, and Other Android layers, it is simple and clear enough to explain the case. This series of articles explains the internal implementation mechanism of the LOG mechanism. This article is part 3 of this series, interpreting android. util. the JNI Implementation of Log, and how to operate the device file to write Log information in the local implementation of c/c ++.

 

 

 

JNI Implementation of Log-like

 

As mentioned above, android. util. Log has two Native methods, which must be implemented in c/c ++ through JNI.

 

<Pre class = "java" name = "code"> public static native boolean isLoggable (String tag, int level );

 

Public static native int println_native (int bufID,

Int priority, String tag, String msg );

 

 

 

These two methods are implemented in frameworks/base/core/jni/android_util_log.cpp. How to Implement JNI is not described here. However, these two methods are transferred to the call of the following two c/c ++ functions.

 

Static jboolean android_util_Log_isLoggable (JNIEnv * env, jobject clazz, jstring tag, jint level)

 

Static jint android_util_Log_println_native (JNIEnv * env, jobject clazz,

Jint bufID, jint priority, jstring tagObj, jstring msgObj)

 

 

Implementation of isLoggable ()

 

The implementation of isLoggable is a comparison between <level> (from the parameter) and the "log. tag. the value of <tag> "(<tag> from parameter) is record if it is greater than or equal. The program implementation snippets are as follows:

 

// LOG_NAMESPACE: "log. tag ."

// Chars: convert from param <tag>

Strncpy (key, LOG_NAMESPACE, sizeof (LOG_NAMESPACE)-1 );

Strcpy (key + sizeof (LOG_NAMESPACE)-1, chars );

 

Len = property_get (key, buf ,"");

Int logLevel = toLevel (buf );

 

Return (logLevel> = 0 & level> = logLevel )? True: false;

 

 

Println_native () Implementation

 

The function android_util_Log_println_native () [in the file android_util.Log.cpp] calls _ android_log_buf_write () [File system/core/liblog/logd_write.c]. _ Android_log_buf_write () organizes parameters and calls the write_to_log function pointer.

 

The write_to_log function pointer is the key to implementation.

 

See the definition of write_to_log:

 

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;

 

Write_to_log initially points to the _ write_to_log_init () function. Therefore, when write_to_log is executed for the first time, _ write_to_log_init () is executed (). If write_to_log is not executed for the first time, it has been modified in _ write_to_log_init () to point to _ write_to_log_kernel ().

 

First look at the implementation of _ 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 );

}

 

Basically, mutual access protection is implemented. If it is the first call (write_to_log also points to _ write_to_log_init (), the corresponding device file is opened to obtain the descriptor, and point write_to_log to _ write_to_log_kernel (). Then, write the file in _ write_to_log_kernel.

 

Look at the implementation of _ write_to_kernel (), which is basically a write operation:

 

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;

}

 

 

To sum up, the println_native () operation is to open the device file (if it has not been opened) and then write data. But how to write it depends on the implementation of the Logger driver of the Log device.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.