转自:http://blog.csdn.net/yihongyuelan/article/details/46409389

isLoggable是什么

Android源码中,我们经常可以看到如下代码:

  1. //packages/apps/InCallUI/src/com/android/incallui/Log.java
  2. public static final String TAG = "InCall";
  3. public static final boolean DEBUG = android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
  4. public static void d(String tag, String msg) {
  5. if (DEBUG) {
  6. android.util.Log.d(TAG, delimit(tag) + msg);
  7. }
  8. }
  9. //packages/apps/InCallUI/src/com/android/incallui/InCallPresenter.java
  10. private InCallState startOrFinishUi(InCallState newState) {
  11. Log.d(this, "startOrFinishUi: " + mInCallState + " -> " + newState);
  12. //... ...
  13. }

只有在android.util.Log.isLoggable返回值为true的时候,startOrFinishUi的log才能正常输出。那什么时候isLoggable才会返回true呢?如何简单快捷的开启isLoggable并使log正常输出呢?

本文来自http://blog.csdn.NET/yihongyuelan 转载请务必注明出处

isLoggable定义

什么是isLoggable?isLoggable是android.util.Log提供的方法,用于检查指定TAG的level,是否满足输出条件,如满足则返回true反之则返回false。isLoggable在源码中的定义如下:

  1. /**
  2. * Checks to see whether or not a log for the specified tag is loggable at the specified level.
  3. *
  4. *  The default level of any tag is set to INFO. This means that any level above and including
  5. *  INFO will be logged. Before you make any calls to a logging method you should check to see
  6. *  if your tag should be logged. You can change the default level by setting a system property:
  7. *      'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>'
  8. *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
  9. *  turn off all logging for your tag. You can also create a local.prop file that with the
  10. *  following in it:
  11. *      'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
  12. *  and place that in /data/local.prop.
  13. *
  14. * @param tag The tag to check.
  15. * @param level The level to check.
  16. * @return Whether or not that this is allowed to be logged.
  17. * @throws IllegalArgumentException is thrown if the tag.length() > 23.
  18. */
  19. public static native boolean isLoggable(String tag, int level);

从以上定义中可以知道:

1. isLoggable默认level为android.util.Log.INFO;

2. 只有 level >= INFO才能输出,即level >= INFO时isLoggable返回true,反之则返回false;

3. 可以通过setprop log.tag.<YOUR_LOG_TAG> <LEVEL>来改变log的默认level,如adb shell setprop log.tag.InCall D。也可以将这些属性按照log.tag.InCall=D的形式,写入/data/local.prop中;

4. tag的长度如果超过23个字符则会抛出IllegalArgumentException异常;

在android.util.Log类中定义了Log的6种Level,如下:

  1. /**
  2. * Priority constant for the println method; use Log.v.
  3. */
  4. public static final int VERBOSE = 2;
  5. /**
  6. * Priority constant for the println method; use Log.d.
  7. */
  8. public static final int DEBUG = 3;
  9. /**
  10. * Priority constant for the println method; use Log.i.
  11. */
  12. public static final int INFO = 4;
  13. /**
  14. * Priority constant for the println method; use Log.w.
  15. */
  16. public static final int WARN = 5;
  17. /**
  18. * Priority constant for the println method; use Log.e.
  19. */
  20. public static final int ERROR = 6;
  21. /**
  22. * Priority constant for the println method.
  23. */
  24. public static final int ASSERT = 7;

6种level对应不同等级的log,level值的大小随着log权重的升高而增大。

isLoggable使能方法

前文提到,在自定义的Log类中通常使用isLoggable来判断是否输出log,如代码:

  1. //packages/apps/InCallUI/src/com/android/incallui/Log.java
  2. public static final String TAG = "InCall";
  3. public static final boolean DEBUG = android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
  4. public static void d(String tag, String msg) {
  5. if (DEBUG) {
  6. android.util.Log.d(TAG, delimit(tag) + msg);
  7. }
  8. }
  9. //packages/apps/InCallUI/src/com/android/incallui/InCallPresenter.java
  10. private InCallState startOrFinishUi(InCallState newState) {
  11. Log.d(this, "startOrFinishUi: " + mInCallState + " -> " + newState);
  12. //... ...
  13. }

如果想要输出startOrFinishUi()方法中的log,可以采用以下方式:

①. 将Log.d修改为android.util.Log.d;使用android.util.Log类取代InCallUI自定义的Log类,重新编译系统APP并push到手机中即可;

②. 修改com.android.incallui.Log中的DEBUG限制;将DEBUG的值直接置为true,或者注释掉if(DEBUG)。也可以将isLoggable(TAG, android.util.Log.DEBUG)中的android.util.Log.DEBUG修改为android.util.Log.INFO,即将log的level增大,从而使isLoggable()返回true并使得DEBUG的值为true;

③. 设置log.tag.InCall的属性值;通过adb shell setprop log.tag.InCall D,或者将"log.tag.InCall=D"写入/data/local.prop中(不包含引号,如local.prop不存在则需自行创建,权限设为644)。根据定义中的描述,设置属性值需要在方法被调用之前,因此需要重启InCallUI进程。通过修改属性值的方法,从而使得isLoggable()的返回值为true,从而使得DEBUG的值为true。

第一种方式直接修改,简单粗暴,但若修改点较多则比较麻烦,且需要重新编译代码。

第二种方式修改点统一,但和第一种一样,也需要重新编译。

第三种使用属性的方式使得isLoggable返回true,这种方式比较方便,同时适用于user/userdebug/eng各个版本的设备。这种方式需要在方法被调用前设置log.tag.InCall,通过代码:

  1. public static final boolean DEBUG = android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);

可以知道,因为DEBUG是static的变量,所以当Log类被加载时,其值就已经设置好了。如果要使得isLoggable返回为true,那么setprop需要在Log类被加载前设置好,因此使用setprop之后需要重启对应的进程,如这里的com.android.incallui。但在framework中有些代码也使用isLoggable,framework属于每一个进程,如何重启framework呢?可以使用:

  1. adb shell stop
  2. adb shell start

adb shell stop会杀掉zygote进程以及所有由zygote孵化而来的子进程。adb shell start则会重启zygote进程,再由zygote进程启动其它Android核心进程。当zygote重新启动时,会重新加载framework相关资源,而此时属性已经设置。这种方法虽然简单,但当设备重启后,所有设置的log.tag.<TAG>都会失效,若想再次启用则需重新设置。

也可以通过将log.tag.InCall=D加入到/data/local.prop文件中,这种方式与setprop类似,都是设置属性值,但这种方式的好处是,设置之后重启设备该log.tag.InCall依然有效。不过因为/data目录的权限控制,只有userdebug/eng版本才可以修改/data/local.prop文件。[/system/core/init/property_service.c] load_override_properties()函数中有/data/local.prop的使能方法。

小结

isLoggable的使能方法如下图所示:

图 1 isLoggable使能方案对比

如果只是想启用某个进程的isLoggable方法,通过setprop设置属性是不错的选择,同事,想要重启设备后依然有效则需要设置/data/local.prop,不过/data目录只有在userdebug/eng版本中才可以写入。那如果想在user版中设置log.tag属性并在重启后依然有效,可以采取以下方法:

1. 获取user版系统的root权限;

2. 将log.tag.InCall=D追加到/system/build.prop文件中;

3. adb reboot重启设备;

以上方案大家可能会疑惑,既然user版获取到了root权限,为什么不直接修改/data/local.prop呢?这是因为如果是user版,则ro.debuggable=0,所以系统启动时不会读取/data/local.prop文件,并最终导致设置log.tag属性不会生效。详细原理将在下一篇文章《Android 5.0 如何正确启用isLoggable(一)__原理分析》中探讨。

 

Android 5.0 如何正确启用isLoggable(一)__使用详解的更多相关文章

  1. Android 5.0 怎样正确启用isLoggable(一)__使用具体解释

    isLoggable是什么 在Android源代码中,我们常常能够看到例如以下代码: //packages/apps/InCallUI/src/com/android/incallui/Log.jav ...

  2. Android 5.0 怎样正确启用isLoggable(二)__原理分析

    前置文章 <Android 5.0 怎样正确启用isLoggable(一)__使用具体解释> 概要 在上文<Android 5.0 怎样正确启用isLoggable(一)__使用具体 ...

  3. Android5.0如何正确启用isLoggable(二) 理分析

    转自:http://www.it165.net/pro/html/201506/43374.html 概要 在上文<Android 5.0 如何正确启用isLoggable(一)__使用详解&g ...

  4. Android 4.0以后正确的获取外部sd卡存储目录

    刚解决这个棘手的问题 找了很久,随笔记下. 网上搜索 android 获取外部sd卡存储目录 普遍都是: 1) Environment.getExternalStorageDirectory() 这个 ...

  5. Android零基础入门第80节:Intent 属性详解(下)

    上一期学习了Intent的前三个属性,本期接着学习其余四个属性,以及Android系统常用内置组件的启动. 四.Data和Type属性 Data属性通常用于向Action属性提供操作的数据.Data属 ...

  6. Android零基础入门第19节:Button使用详解

    原文:Android零基础入门第19节:Button使用详解 Button(按钮)是Android开发中使用非常频繁的组件,主要是在UI界面上生成一个按钮,该按钮可以供用户单击,当用户单击按钮时,按钮 ...

  7. Android四大组件之——Activity的生命周期(图文详解)

        转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:JohnTsai.Work@gmail.com       [Andro ...

  8. 《从0到1学习Flink》—— Flink 配置文件详解

    前面文章我们已经知道 Flink 是什么东西了,安装好 Flink 后,我们再来看下安装路径下的配置文件吧. 安装目录下主要有 flink-conf.yaml 配置.日志的配置文件.zk 配置.Fli ...

  9. Android View 的绘制流程之 Layout 和 Draw 过程详解 (二)

    View 的绘制系列文章: Android View 的绘制流程之 Measure 过程详解 (一) Android View 绘制流程之 DecorView 与 ViewRootImpl 在上一篇  ...

随机推荐

  1. JS对于数据常见操作

    var _mozi=['墨家','墨子','墨翟','兼爱非攻','尚同尚贤']; $.each(_mozi,function(key,val){//先key 后值 循环 console.log(ke ...

  2. Android_bug之Default Activity not found

    在运行自己修改默认的MainActivety,运行自己的Mainactivety时,碰到这个问题Could not identify launch activity: Default Activity ...

  3. tfw格式图解

    话不多说,直接看图. 上图中的UV坐标,实际上只的是图像的 横向坐标 和 纵向坐标 .即图像的行和列坐标. 对于图上任意一个像素点(col,row)这个坐标,换算其地理坐标就十分简单. GeoX = ...

  4. Java Log4j日志使用

    在程序中使用log4j 1.导入包import org.apache.log4j.Logger;import org.apache.log4j.PropertyConfigurator; 2.获取lo ...

  5. css3 transition的各种ease效果

    http://www.w3school.com.cn/tiy/t.asp?f=css3_transition-timing-function2 linear 平均速度 ease 快启动,慢停止,物理原 ...

  6. android通过BitmapFactory.decodeFile获取图片bitmap报内存溢出的解决办法

    android通过BitmapFactory.decodeFile获取图片bitmap报内存溢出的解决办法 原方法: public static Bitmap getSmallBitmap(Strin ...

  7. Qt ini配置文件读写

    #include <QSettings> void MainWindow::saveIni() { //如果ini文件不存在,创建新ini文件,存在赋值 QSettings *setIni ...

  8. python(pyqt)开发环境搭建

    eric+pyqt 安装(python开发工具) 更多 0 Python python Eric是一个开源的.跨平台的python&ruby集成开发环境,基于python和pyqt运行.eri ...

  9. BestCoder25 1001.Harry and Magical Computer(hdu 5154) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5154 题目意思:有 n 门 processes(编号依次为1,2,...,n),然后给出 m 种关系: ...

  10. 对map创建出来的值顺序排序问题

    TreeMap 在用Ajax动态创建checkBox时,而把值放在了HashMap中,hashMap是无序的,因此你动态创建出来的顺序是乱的,比如你想要的顺序是1.2.3.4但出来的结果可能是 3.2 ...