How to correctly enable isLoggable in Android 5.0 (ii) _ Principle Analysis, androidisloggable

Source: Internet
Author: User

How to correctly enable isLoggable in Android 5.0 (ii) _ Principle Analysis, androidisloggable
Pre-article

How to correctly enable isLoggable in Android 5.0 (1) _ Usage Details

Summary

The usage of isLoggable is analyzed in "how to correctly enable isLoggable in Android 5.0 (I) _ Usage Details, this article mainly analyzes the implementation principle of isLoggable and the principle of permanent enable isLoggable after the root user system, and uses scripts to automatically set isLoggable attributes.

This article from http://blog.csdn.net/yihongyuelan reprint please be sure to indicate the source

How isLoggable works

IsLoggable is defined in frameworks/base/core/java/android/util/Log. java:

    /**     * 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);
The native Implementation of isLoggable is in frameworks/base/core/jni/android_util_Log.cpp:
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 },}; static jboolean android_util_Log_isLoggable (JNIEnv * env, jobject clazz, jstring tag, jint level ){//...... omit 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 % zu characters \ n", chars, PROPERTY_KEY_MAX-sizeof (LOG_NAMESPACE); jniThrowException (env, "java/lang/IllegalArgumentException", buf2);} else {// call the local isLoggalbe Method result = isLoggable (chars, level);} env-> ReleaseStringUTFChars (tag, chars ); return result ;}
The Code shows that the returned value of android_util_Log_isLoggable () depends on the isLoggable () method in android_util_Log.cpp:
# Define LOG_NAMESPACE "log. tag. "static jboolean isLoggable (const char * tag, jint level) {String8 key; key. append (LOG_NAMESPACE); key. append (tag); char buf [PROPERTY_VALUE_MAX]; // get the attribute log. tag. <Your_TAG> value if (property_get (key. string (), buf, "") <= 0) {buf [0] = '\ 0';} int logLevel = toLevel (buf ); return logLevel> = 0 & level> = logLevel ;}
The isLoggable () in android_util_Log.cpp first obtains the log through property_get. tag. <Your_TAG> attribute value. If this attribute is not set, set buf [0] to null. Then, use the toLevel () method to obtain the value of logLevel, the final return value is determined by logLevel> = 0 & level> = logLevel. The content of the toLevel () method is as follows:
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;}
Levels is the levels_t object. The value is assigned in the register_android_util_Log () method, while the register_android_util_Log () method uses AndroidRuntime at system startup. REG_JNI (register_android_util_Log) in cpp completes the call. The Code is as follows:
Struct levels_t {jint verbose; jint debug; jint info; jint warn; jint error; jint assert ;}; static levels_t levels; int register_android_util_Log (JNIEnv * env) {jclass clazz = FindClassOrDie (env, "android/util/Log"); // obtain android. util. the VERBOSE/DEBUG/INFO/WARN/ERROR/ASSERT value in the Log and is assigned to levels. verbose = env-> GetStaticIntField (clazz, GetStaticFieldIDOrDie (env, clazz, "VERBOSE", "I"); levels. debug = env-> GetStaticIntField (clazz, distinct (env, clazz, "DEBUG", "I"); levels.info = env-> GetStaticIntField (clazz, GetStaticFieldIDOrDie (env, clazz, "INFO", "I"); levels. warn = env-> GetStaticIntField (clazz, GetStaticFieldIDOrDie (env, clazz, "WARN", "I"); levels. error = env-> GetStaticIntField (clazz, GetStaticFieldIDOrDie (env, clazz, "ERROR", "I"); levels. assert = env-> GetStaticIntField (clazz, GetStaticFieldIDOrDie (env, clazz, "ASSERT", "I"); return RegisterMethodsOrDie (env, "android/util/Log", gMethods, NELEM (gMethods ));}
In the toLevel () method, if the character array value [0] matches V/D/I/W/E/A/S, the corresponding Int value is returned, if value [0] is null, the default value levels.info is 4. Check the isLoggable () method in android_util_Log.cpp again:
Static jboolean isLoggable (const char * tag, jint level ){//...... int logLevel = toLevel (buf) is omitted; return logLevel> = 0 & level> = logLevel ;}
Because the data in the levels struct is from android. util. Log, the minimum value is 2 (VERBOSE), and the maximum value is 7 (ASSERT), so logLevel> = 0 is always true. Level> = logLevel is determined based on the level specified by the user, as shown in figure
android.util.Log.isLoggable("InCall", android.util.Log.DEBUG);

The level here is DEBUG, that is, 3, which is equivalent to level> = logLevel to 3> = logLevel. If the attribute value log is not set. tag. if the value of InCall is not set, logLevel returns 4 (INFO) by default. Therefore, if 3> = 4 is not set, false is returned. Therefore, logLevel> = 0 & level> = logLevel returns false; if you set log. tag. if the InCall value is D or V, logLevel returns 3 or 2. Therefore, level> = logLevel is true, so that isLoggable returns true.

About Android Property System

Attribute Value reading is involved in the isLoggable call process. Here, we will briefly understand the workflow of the Android Property System. As shown in:


Figure 1 android property system (Pic From @ rxwen)

Blue indicates independent processes, orange indicates shared memory, and white indicates attribute files. The property value is obtained through the property consumer. When the system starts, the property value in the persistent file is loaded into the shared memory. If you need to set the property value, the property setter submits the request to the property service through socket, and the property service writes the property value to the shared memory.

Because set attributes such as log. tag. inCall D is written into the shared memory, but after the device restarts, it will re-apply for the shared memory and load the property file, but the manually set property does not write the property file, so after the device is restarted, log. tag. the InCall attribute is invalid.

Local. prop file loading process

As mentioned in the previous article "how to correctly enable isLoggable (1) _ Usage Details in Android 5.0. tag. <Your_Tag> If the attribute is still valid, you need to set log. tag. inCall = D write/data/local. in the prop file, after the device is restarted, the system will load the property file under this path. How is this step completed? This involves the initialization process of the Android Property System.

The Android Property Service is initialized in the Init process. During the initialization process, the Property file in the specified path is loaded. The loading process is shown in:


Figure 2 Property files init flow

The figure shows the file path:

/System/core/init. cpp

/System/core/init/init_parser.cpp

/System/core/init/builtins. cpp

/System/core/init/property_service.cpp

/System/core/rootdir/init. rc

After the init process starts, execute the main () method first, and then load init through init_parse_config_file. rc file, and init. the rc file is parsed, And the parsed service, action, and command are stored in the linked list. After init. rc resolution is completed, extract the commands in the linked list one by one using the execute_one_command () method and execute them. The properties-related actions in init. rc are as follows:

# Load properties from /system/ + /factory after fs mount.on load_all_props_action    load_all_props    start logd-reinit
Load_all_props is defined in/system/core/init/keywords. h:
#ifndef KEYWORD//... ...#define __MAKE_KEYWORD_ENUM__#define KEYWORD(symbol, flags, nargs, func) K_##symbol,enum {    K_UNKNOWN,#endif    //... ...    KEYWORD(load_persist_props,    COMMAND, 0, do_load_persist_props)    KEYWORD(load_all_props,        COMMAND, 0, do_load_all_props)    //... ...#ifdef __MAKE_KEYWORD_ENUM__    KEYWORD_COUNT,};#undef __MAKE_KEYWORD_ENUM__#undef KEYWORD#endif
Finally, it is called to the load_all_props () method of/system/core/init/property_service.cpp:
void load_all_props() {    load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);    load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);    load_properties_from_file(PROP_PATH_BOOTIMAGE_BUILD, NULL);    load_properties_from_file(PROP_PATH_FACTORY, "ro.*");    load_override_properties();    /* Read persistent properties after all default values have been loaded. */    load_persistent_properties();}

Expand the load_override_properties () method and you can see:

static void load_override_properties() {    if (ALLOW_LOCAL_PROP_OVERRIDE) {        char debuggable[PROP_VALUE_MAX];        int ret = property_get("ro.debuggable", debuggable);        if (ret && (strcmp(debuggable, "1") == 0)) {            load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);        }    }}

Use load_properties_from_file () and load_override_properties () to load attribute files. The paths of these files are defined in/bionic/libc/include/sys/_ system_properties.h:
#define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"#define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"#define PROP_PATH_VENDOR_BUILD     "/vendor/build.prop"#define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"#define PROP_PATH_FACTORY          "/factory/factory.prop"
Note that/system/build. prop,/vendor/build. prop,/factory. prop files will be loaded if they exist, and/data/local. the prop file is only available in ro. debuggable = 1 is loaded, that is,/data/local. prop is loaded by the system only when userdebug/eng is used. Enable the isLoggable principle permanently in the user System

In the previous article "how to correctly enable isLoggable (1) _ Usage Details" in Android 5.0, we have provided methods to enable isLoggable and compared the advantages and disadvantages of various methods. If the current device is a user, you can enable isLoggable permanently after obtaining the root permission. The preceding analysis shows that in the user system,/data/local. the prop property file will not be read by the property service, but/system/build. the prop attribute file is read in both user and userdebug/eng versions. tag. <Your_Tag> append to/system/build. in the prop file.

You can also use the following script (Windows) to set the attribute value of isLoggable (adbd can use adb remount to obtain the root permission ):

@echo offecho ============= Open Hidden Logs =============echo =============   version 0.2  =============echo =============     20150605   =============echo =============      SEVEN     =============REM Update:REM 1. Rename the script to OpenHiddenLogs.bat.REM 2. Adaptation of user mode device.REM 3. Add the instructions and steps.REM Instructions:REM This script is used to enable some hide logs in Android Platforms.REM Android property system provides an approach to enable isLoggable(String tag, int level).REM You'll find some code in Android as below:REM private static final String TAG = "Telecom";REM public static final boolean DEBUG = android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);REM if (DEBUG) {REM    android.util.Log.d(TAG, getPrefix(obj) + str1 + str2);REM }REM If you want to enable the Log.d(), you need to type "adb shell setprop log.tag.Telecom V"REM in your console, and kill the process of com.android.server.telecom, then Log.d() is enabled.REM But if you reboot your device, the Log.d() is disabled, so we write the TAG to property systemREM to enable Log.d() forever. If you have any questions, please feel free to let me know.REM Email: yihongyuelan@gmail.comREM Steps:REM 1. Get your device root permission.REM 2. Running the OpenHideLogs.bat;echo.set NOROOTSTR=adbd cannot run as rootset ROOTSTR=adbd is already running as rootset BUILDTYPE=userfor /f "delims=" %%a in ('adb shell getprop ro.build.type') do set "build_type=%%a"echo Your device is %build_type% Modeecho.:ISENABLEDfor /f "delims=" %%c in ('adb shell getprop log.tag.InCall') do set "check=%%c"if "%check%" == "V" (echo Hidden Logs has been enabled!pauseexit) else (echo Hidden Logs hasn't been enabled! )echo.for /f "delims=" %%b in ('adb root') do set "str=%%b"REM echo %str%set EXISTS_FLAG=falseecho %str%|find "%ROOTSTR%">nul&&set EXISTS_FLAG=trueif "%EXISTS_FLAG%"=="true" (echo Checking ROOT permission PASSping -n 5 127.0.0.1 >nuladb remountif "%build_type%" == "%BUILDTYPE%" (adb shell "echo log.tag.InCall=V >> /system/build.prop"adb shell "echo log.tag.Telephony=V >> /system/build.prop"adb shell "echo log.tag.Telecom=V >> /system/build.prop"adb shell "echo log.tag.TelecomFramework=V >> /system/build.prop"adb shell "echo log.tag.Mms=V >> /system/build.prop"adb shell "echo log.tag.MessageTemplateProvider=V >> /system/build.prop"adb shell "echo log.tag.CarrierText=V >> /system/build.prop") else (adb push local.prop /data/adb shell chmod 644 /data/local.propadb shell chown system:system /data/local.prop)adb rebootadb wait-for-devicegoto :ISENABLED) else (echo Checking ROOT permission FAILecho Please get the root privileges for adbd and try againpauseexit)
The content of local. prop is as follows:
log.tag.InCall=Vlog.tag.Telephony=Vlog.tag.Telecom=Vlog.tag.TelecomFramework=Vlog.tag.Mms=Vlog.tag.MessageTemplateProvider=Vlog.tag.CarrierText=V
The script is synchronously updated to github. For more information, see github.

Summary

At first, we saw android. util. log. isLoggable (TAG, android. util. log. DEBUG) Code. It is assumed that isLoggable will return true in the userdebug version. After the result is viewed, the related log is not printed. After further analysis, the implementation principle behind isLoggable is found, at the same time, I realized the flexibility of using isLoggable to control log output. For developers, you can use isLoggable to enable the hidden log in the user version system to provide more detailed logs for related issues. The important knowledge points of isLoggable are summarized as follows:

1. The default isLoggable threshold is 4 (INFO)

If the log level is less than 4 (INFO), namely 3 (DEBUG) and 2 (VERBOSE), isLoggable returns false;

2. isLoggable can return true by setting the attribute value

By setting log. tag. the attribute of InCall D can make the corresponding isLoggable return true, but note that the relevant process needs to be restarted after setting the attribute, you can also use adb shell stop & adb shell start to restart Zygote and its sub-processes. However, this method fails after the device is completely restarted;

3. Set the attribute file to enable isLoggable to return true permanently.

In the userdebug/eng version, you can write the attribute value log. tag. InCall = D to the/data/local. prop file. In this way, isLoggable returns true and remains valid after the device is restarted. If the root permission has been obtained in the user system, you can append the attribute value to/system/build. prop, or enable isLoggable to return true permanently after restart;

Refer:

In-depth explanation of the Android Property mechanism: This article analyzes in detail the processes of Android 4.4 Android Property.

Android init process (II): initialization language (init. rc) parsing: This article analyzes the parsing process of init. rc in detail. Note that in the parsing process, nargs will first execute nargs ++

Android SystemProperties setting/Obtaining System Properties usage summary: This article is a collection of Android Property systems.


Download related resources without points: click here

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.